1. 需求场景
在服务器上实现对特定网页截图
2. 使用工具
- selenium
- xvfb
3. 开发流程
1. Python脚本对网页截图功能的实现
```python from selenium import webdriver
url = raw_input(“Please input URL:”) save_fn = raw_input(“Please input filename:”)
browser = webdriver.Firefox() browser.set_window_size(1200, 900) browser.get(url) browser.save_screenshot(save_fn) browser.close()
1
2
3
#### 2. 服务器端没有Xwindow如何截图
xvfb工具相当于一个wrapper, 给应用程序提供虚拟的 X server
Xvfb 可以直接处理 Window 的图形化功能,並且不會把图像输出到屏幕上,也就是说,就算你的电脑沒有启动 Xwindow , 你仍然可以执行图形程序。
sudo apt-get install xvfb export DISPLAY=:10 xvfb-run python capture.py
1
2
3
4
#### 3. 浏览器的选择
PhantomJs、Firefox、Chrome
`apt-get install phantomjs`
driver = webdriver.PhantomJS()
1
2
为什么不用PhantomJs: 动态加载页面效果不好
chrome 使用前需要先下载一个chromedriver, 并在使用时指定该文件
browser = webdriver.Chrome(executable_path=’/usr/lib/chromium-browser/chromedriver’, chrome_options=chrome_options)
1
2
* firefox 版本问题
在使用selenium和Firefox组合的时候很多情况下会遇到兼容问题,比如下面这种:
File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/firefox_binary.py”, line 99, in _wait_until_connectable “The browser appears to have exited “ selenium.common.exceptions.WebDriverException: Message: The browser appears to have exited before we could connect. If you specified a log_file in the FirefoxBinary constructor, check it for details.
1
2
3
4
5
6
7
8
解决办法:
* 升级selenium
* 安装firefox旧版本
https://www.liberiangeek.net/2012/04/how-to-install-previous-versions-of-firefox-in-ubuntu-12-04-precise-pangolin/
#### 4. 截图时遇到的一些问题:
* 长网页截图
对于一些比较长的网页,为了节省网页加载时间,很多下面的内容只有在你下滑到那个地方的时候才会加载,我们可以用browser执行一段js代码来实现滚动条的滚动
browser.execute_script(“”” (function () { var y = 0; var step = 100; window.scroll(0, 0);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function f() {
if (y < document.body.scrollHeight) {
y += step;
window.scroll(0, y);
setTimeout(f, 50);
} else {
window.scroll(0, 0);
document.title += "scroll-done";
}
}
setTimeout(f, 1000);
})();
""") ``` * 弹窗 可以在预期有弹窗的网页捕获弹窗并关闭 ```Python from selenium.common.exceptions import NoAlertPresentException # 2.16版本以上 browser.get(url) # Load page alert = browser.switch_to.alert try:
alert.dismiss() except NoAlertPresentException:
pass ``` * 视频播放 or 长时间无响应 1. set timeout `browser.set_page_load_timeout(3*60)` 2. 函数计时装饰器 ``` def timeout(seconds, error_message="Timeout Error: the cmd 30s have not finished."):
def decorated(func):
result = ""
def _handle_timeout(signum, frame):
global result
result = error_message
raise TypeError(error_message)
def wrapper(*args, **kwargs):
global result
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return result
return functools.wraps(func)(wrapper)
return decorated
@timeout(3*60, ‘超时退出’) def capture(url, save_fn=”capture.png”): …
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
* 不通国家打开内容不一样——代理
* Firefox
可以设置http代理、ssl代理和socks代理
```Python
profile = webdriver.FirefoxProfile()
profile.set_preference('network.proxy.type', 1)
# profile.set_preference("network.proxy.http", "127.0.0.1")
# profile.set_preference("network.proxy.http_port", 1080)
# profile.set_preference("network.proxy.ssl", "127.0.0.1")
# profile.set_preference("network.proxy.ssl_port", 1080)
profile.set_preference('network.proxy.socks', "127.0.0.1")
profile.set_preference('network.proxy.socks_port', 1080)
profile.update_preferences()
browser = webdriver.Firefox(firefox_profile=profile)
- Chrome ``` proxy = ‘127.0.0.1:1080’ chrome_options = webdriver.ChromeOptions() chrome_options.add_argument(‘–proxy-server=socks5://%s’ % proxy)
browser = webdriver.Chrome(executable_path=’/usr/lib/chromium-browser/chromedriver’, chrome_options=chrome_options)
1
2
3
4
5
* 网页跳转
1. find element , by_id, by_div, by_class, by_xpath
2. click, 点击元素跳转网页
3. switch handler, browser切换到新打开的网页。
from selenium.webdriver.common.by import By browser.find_elements(By.XPATH, xpath)[0].click() time.sleep(10) for handle in browser.window_handles: browser.switch_to.window(handle) browser.save_screenshot(save_fn) browser.close()
1
2
3
4
* 产生大量缓存文件
selenium执行时会在/tmp文件夹产生大量的浏览器临时文件,关闭程序后并没有自动清楚。
解决办法:
每次运行前自动清理/tmp文件夹, 递归删除
import os def delete_file_folder(src): ‘'’delete files and folders’’’ if os.path.isfile(src): try: os.remove(src) except: pass elif os.path.isdir(src): for item in os.listdir(src): itemsrc=os.path.join(src,item) delete_file_folder(itemsrc) try: os.rmdir(src) except: pass
delete_file_folder(‘/tmp’) ```