任其崩溃思想在爬虫中的应用

一个同学的项目需要一些网站的首页的截图,网站数量大概有几千个,这么多的网站当然要用爬虫去爬了

百度出来一个看起来靠谱的方法,用了selenium库,例程如下:

1
2
3
4
5
6
7
from selenium import webdriver 
url = "http://baidu.com"
picName = "baidu.png"
brower=webdriver.Chrome()
brower.get(url)
brower.save_screenshot(picName)
brower.close()

试了一下很成功,然而真正用起来却踩了无数的坑

  1. 网页下载图片是需要时间的,而brower.get(url)这个函数不等到所有的资源都加载完是不会退出的
  2. 几千个网址里面有一些是已经废弃的假网站,brower.get(url)无法识别出来,只会一直等它们返回内容
  3. brower=webdriver.Chrome() 会打开一个浏览器窗口,据我观察发现,如果这个浏览器打开网页后出现了网址跳转,拒绝连接等情况,python程序就不能控制这个浏览器窗口了,导致brower.close()不能正常执行,浏览器关不掉

于是我对于各个问题都研究出了解决方案

  1. 针对第一个坑,使用browser.set_page_load_timeout(10)给网页加载设定一个时限,如果超时的话就会抛出TimeoutException异常,然后我们再执行browser.execute_script('window.stop()') 用javascript使网页停止加载。
  2. 第二个坑,是对方网站坑我们,所以我们就不截图了。但是如果程序一直阻塞也不是办法,所以还是给程序设定一个时限,如果超时就强制停止。这里我用的是@timeout_decorator.timeout(12)这个装饰器
  3. brower.close()关不掉浏览器,那就直接调用shell命令kill掉不就行了

无数次debug后,我终于写出了能用的代码。
回过头来一想,“浏览器崩了就崩了,直接kill掉”这个操作不就是“let it crash”思想的体现吗。有了异常情况如果不能正确处理,就应该任其崩溃,而不是以错误状态继续执行

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
40
41
42
43
from selenium import webdriver 
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import TimeoutException
import csv
import threading
import timeout_decorator
import os
csvName = "out.csv"

@timeout_decorator.timeout(12) # 如果12秒内函数没有执行完,就停止,抛出timeout异常
def shot(browser, url,picName):
print( url , picName)
try:
browser.get(url) # 打开网页
except TimeoutException as err:
print(err)
browser.execute_script('window.stop()') # 用javascript使网页停止加载
finally:
browser.save_screenshot(picName) # 截图

def main():
with open(csvName) as f:
reader = csv.reader(f)
cnt = 1
for i in list(reader):
url = i[3] # 网址
if cnt%10 == 0: # 执行shell命令杀死所有chrome进程
os.system("ps -aux | grep chrome | grep -v grep | awk '{print $2}' | xargs kill")
picName = str(cnt) + ".png" # 图片名称
cnt=cnt+1
browser = webdriver.Chrome() # 打开浏览器
browser.set_page_load_timeout(10) # 如果10秒内网页没有加载完,抛出timeout异常
browser.set_window_size(1300,704) # 设定窗口大小
try:
shot(browser,url,picName)
except Exception as err:
print(err)
finally:
browser.quit() # 关闭浏览器

if __name__ == '__main__':
main()


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!