使用Selenium在服务器上对网页截图

Posted by FridayLi on August 20, 2017

1. 需求场景

在服务器上实现对特定网页截图

2. 使用工具

  1. selenium
  2. 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’) ```

参考文章

  1. firefox 代理设置
  2. How to Install Previous Versions of Firefox