• Python抓取网页的性能问题


    Python抓取网页的性能问题 - 熊猫凶猛 - 博客园

    Python抓取网页的性能问题

    抓取网页过程中,软件的性能瓶颈当然是网络连接,这是第一时间可以想到的。此外,通过cProfile.run和pstats.Stats,也可以清楚地看出来。一般来说,可以通过下面几个方法来解决这个问题:

    1. 通过threading与multiprocessing来解决,例如
      复制代码
      #urls 包含所有需要扫描的URL
      #lists包含每个线程扫描的结果的列表的列表
      lists = []
      threads = []
      for i in range(10):
          temp = []
          lists.append(temp)
          t = threading.Thread(target = check_page, args = ([_ for _ in urls if urls.index(_) % 10 == i], temp))
          t.start()
          threads.append(t)
      
      for t in threads: t.join()
      复制代码
    2. 如果不需要获取完整网页的话,可以在请求的HTTP Header中加入接收Range的头部,只获取一部分网页:
      req = urllib2.Request(url, headers = {"Range": "bytes=0-1023"})

      不过需要注意的一点是有少部分网站不支持Range这个头部,在这个时候需要去掉这个头部重新请求才行

    3. 在请求的HTTP Header中加入接收gzip编码内容的头部:
      req = urllib2.Request(url, headers = {"Accept-Encoding": "gzip"})

      至于如何判断是否返回的真是gzip编码的内容,以及如何解gzip编码的内容,在我另一篇文章里有

    4. 别忘了在urlopen的时候加上timeout

    在使用threading和multiprocessing的过程中,感觉这两者至少在扫描网页时性能相差不大,我分别创建了10个线程和10个进程扫描大约8K+个不同网站的页面,三次对比时间相差少于10%,而multiprocessing占用系统内存较多。

    其实除了上述方法外,在Python里还有一些可能更好的提高性能的地方。例如使用greenlet、stackless python等支持更好多线程多进程的工具,还可以使用异步IO,例如twisted或者PycURL。不过个人对greenlet不熟,觉得twisted实在太twisted,PycURL不够pythonic,而stackless python怕破坏了其他python程序,因此仍然使用urllib2 + threading方案。当然,因为GIL的问题,python多线程仍然不够快,可是对单线程情况来说,已经有数倍时间的节省了。

    除此之外,在多线程环境下如果需要使用lxml来对网页进行解析的时候,时而会出现占用系统所有内存的问题发生,估计是lxml使用的底层的libxslt或者libxml2的库有重入性的问题导致的,这时候需要将lxml解析html的工作放到主线程来做。当然,这会导致系统的性能下降,不过这是lxml库自己的限制,除非启动真正的多进程,不然即使使用multiprocessing也仍然会出错。

    为什么不用BeautifulSoup呢?嗯,这是因为它与它依赖的sgmllib有一些特让人郁闷的bug,还因为它解析HTML比lxml.html慢10倍,这个事就另说了。

  • 相关阅读:
    opencv学习笔记(五)镜像对称
    opencv学习笔记(四)投影
    C++文件读写详解(ofstream,ifstream,fstream)
    C++ 提取字符串中的数字
    opencv学习笔记(三)基本数据类型
    opencv学习笔记(二)寻找轮廓
    分别心
    关于bonecp和QuerRunner
    关于AutoCommit
    一个detect问题引发的一系列思考
  • 原文地址:https://www.cnblogs.com/lexus/p/2472935.html
Copyright © 2020-2023  润新知