优化web-scraper python循环

时间:2016-03-17 16:31:09

标签: python pandas web-scraping

我代表所有者从新闻网站上抓文章。我必须保持每秒<= 5次请求,或者6小时内(晚上)约10万篇文章,但我最多只能获得~30k。

使用Jupyter笔记本,它首先运行良好,但反应越来越少。 6小时后,内核通常是不可中断的,我必须重新启动它。由于我将每篇文章存储在内存中,这是一个问题。

所以我的问题是:有没有更有效的方法来在6小时内达到~100k文章?

代码如下。对于Pandas数据帧列中的每个有效URL,循环:

  1. 下载网页
  2. 摘录相关文字
  3. 清除文本中的一些编码垃圾
  4. 将该文本写入另一个数据框列
  5. 每2000篇文章,它将数据帧保存为CSV(覆盖最后一次备份),以处理脚本的最终崩溃。
  6. 我考虑过的一些想法:

    1. 将每篇文章写入本地SQL服务器而不是in-mem(速度问题?)
    2. 使用其网址在csv中保存每篇文章文本,然后再构建数据框
    3. 删除所有&#34; print()&#34;功能,并完全依赖于日志记录(我的记录器配置似乎没有表现出色,但是 - 我不确定它是否记录了我告诉它的所有内容)

      timer_table = {1, 22, 6, 3, 100, 2}
    4. 这是我正在使用的日志配置。我在SO上发现了它,但是这个特殊的脚本它似乎并不能捕获所有东西。

      i=0
      #lots of NaNs in the column, hence the subsetting
      for u in unique_urls[unique_urls['unique_suffixes'].isnull() == False]\
      .unique_suffixes.values[:]:
      
        i = i+1
      
        if pd.isnull(u): 
            continue
      
        #save our progress every 2k articles just in case
        if i%2000 == 0:
            unique_urls.to_csv('/backup-article-txt.csv', encoding='utf-8')
      
        try:
            #pull the data
            html_r = requests.get(u).text
      
            #the phrase "TX:" indicates start of article 
            #text, so if it's not present, URL must have been bad
            if html_r.find("TX:") == -1: 
                continue
      
            #capture just the text of the article
            txt = html_r[html_r.find("TX:")+5:]
      
            #fix encoding/formatting quirks
            txt = txt.replace('\n',' ') 
            txt = txt.replace('[^\x00-\x7F]','')
      
      
      
            #wait 200 ms to spare site's servers
            time.sleep(.2)
      
            #write our article to our dataframe
            unique_urls.loc[unique_urls.unique_suffixes == u, 'article_text'] = txt
      
      
            logging.info("done with url # %s -- %s remaining", i, (total_links-i))
      
      
            print "done with url # " + str(i)
            print total_links-i
      
        except:
            logging.exception("Exception on article # %s, URL: %s", i, u)
            print "ERROR with url # " + str(i)
            continue
      

      eta:回答/评论的一些细节:

      • 脚本只能在16 GB / ram EC2实例上运行

      • 文章每篇约100-800字

1 个答案:

答案 0 :(得分:1)

根据你的描述,我将采取一种有根据的猜测并说你的脚本将你的机器变成一个交换风暴,因为你得到了大约30k的文章。我在代码中看不到任何可以使用以下内容轻松释放内存的内容:

some_large_container = None

设置你知道的对None有大量分配的东西告诉Python的内存管理器它可用于垃圾收集。你也可能想要明确地调用gc.collect(),但我不确定那对你有多好处。

您可以考虑的替代方案:

  • sqlite3:使用sqlite3作为中间存储,而不是远程SQL数据库。存在一个Python模块。
  • 继续附加到CSV检查点文件。
  • 使用zlib.compress()压缩字符串。

你决定去的任何方式,你可能最好将收集作为第1阶段,将Pandas数据框架构建为第2阶段。永远不要为了聪明一半而付出代价。另一半往往会挂你。