优化此Python代码 - webscraping并将结果输出到CSV文件

时间:2016-07-06 15:35:27

标签: python csv web-scraping beautifulsoup

我正在尝试从几千页中删除数据。我的代码可以正常工作大约100页,但然后显着减慢。我很确定我的类似Tarzan的代码可以得到改进,因此网页抓取过程的速度会提高。任何帮助,将不胜感激。 TIA!

以下是简化代码:

csvfile=open('test.csv', 'w', encoding='cp850', errors='replace')
writer=csv.writer(csvfile)

list_url= ["http://www.randomsite.com"]
i=1

for url in list_url:
 base_url_parts = urllib.parse.urlparse(url)
 while True:
    raw_html = urllib.request.urlopen(url).read()
    soup = BeautifulSoup(raw_html, "lxml")

    #### scrape the page for the desired info 

    i=i+1
    n=str(i)

   #Zip the data
    output_data=zip(variable_1, variable_2, variable_3, ..., variable_10)

#Write the observations to the CSV file
    writer=csv.writer(open('test.csv','a',newline='', encoding='cp850', errors='replace'))
    writer.writerows(output_data)
    csvfile.flush()

    base="http://www.randomsite.com/page"
    base2=base+n
    url_part2="/otherstuff"
    url_test = base2+url_part2

    try:
       if url_test != None:
           url = url_test
           print(url)
       else:
           break
    except: 
       break

csvfile.close()
编辑:感谢所有的答案,我从中学到了很多东西。我(慢慢地!)在Scrapy周围学习。但是,我发现这些页面可以通过批量下载获得,这将是解决性能问题的更好方法。

3 个答案:

答案 0 :(得分:0)

主要的瓶颈是你的代码是同步的(阻塞)。在完成当前URL处理之前,不要继续使用下一个URL。

你需要通过切换到Scrapy来异步制作,这可以解决这个问题,或者通过自己构建一些东西,例如grequests

答案 1 :(得分:0)

如果你想在没有很多复杂代码的情况下快速前进,你需要A)从解析中分离请求(因为解析阻塞了你用来发出请求的线程),以及B)同时发出请求并同时解析它们。所以,我会做几件事:

  1. 使用eventlet异步请求所有页面。我一直在使用Python中的异步http框架,并且发现最容易学习的eventlets。
  2. 每次成功获取页面时,都会将html存储在某处。 A)你可以在本地将它写入单独的html文件,但你手上会有很多文件。 B)您可以将这么多记录存储为字符串(str(source_code))并将它们放在本机数据存储中,只要它是哈希(可能是一个集合或字典)​​。 C)你可以使用超轻量但不是特别高效的数据库,如TinyDB,并将页面源粘贴在JSON文件中。 D)您可以使用第三方库的数据结构进行高性能计算,如Pandas DataFrame或NumPy数组。他们可以轻松存储这么多数据,但可能有点过分。
  3. 检索后分别解析每个文档。使用lxml进行解析将非常快,因此根据您需要的速度,您可以顺利解析文件。如果你想更快,请在python中查找有关多处理的教程。它非常容易学习,并且您可以同时解析X文档,其中X是计算机上可用核心的数量。

答案 2 :(得分:0)

也许这只是简化中的一个错误,但看起来你多次打开'test.csv',但只关闭它一次。当URL数量增加到100以上时,不确定这是否是导致意外放缓的原因,但是如果您希望所有数据都放在一个csv文件中,您可能应该坚持打开文件并将编写器放在顶部,就像您一样已经做了,而不是在循环中做。

另外,在构建新URL的逻辑中:url_test != None总是不正确吗?那你怎么退出循环?在urlopen失败时的异常?然后你应该尝试 - 除了那个。这不是性能问题,但任何一种清晰度都有帮助。