2

我做了一个简单的网络爬虫,使用urllib和beautifulsoup从网页上的表格中提取数据。为了加快数据拉取速度,我尝试使用线程,但出现以下错误: “内部缓冲区错误:内存分配失败:增长缓冲区” 此消息出现不少次,然后显示: “内存不足”Python线程 - 内部缓冲区错误 - 内存不足

感谢您的帮助。

from bs4 import BeautifulSoup 
from datetime import datetime 
import urllib2 
import re 
from threading import Thread 

stockData = [] 

#Access the list of stocks to search for data 
symbolfile = open("stocks.txt") 
symbolslist = symbolfile.read() 
newsymbolslist = symbolslist.split("\n") 

#text file stock data is stored in 
myfile = open("webcrawldata.txt","a") 

#initializing data for extraction of web data 
lineOfData = "" 
i=0 

def th(ur): 
    stockData = [] 
    lineOfData = "" 
    dataline = "" 
    stats = "" 
    page = "" 
    soup = "" 
    i=0 
    #creates a timestamp for when program was won 
    timestamp = datetime.now() 
    #Get Data ONLINE 
    #bloomberg stock quotes 
    url= "http://www.bloomberg.com/quote/" + ur + ":US" 
    page = urllib2.urlopen(url) 
    soup = BeautifulSoup(page.read()) 
    #Extract key stats table only 
    stats = soup.find("table", {"class": "key_stat_data" }) 
    #iteration for <tr> 
    j = 0 
    try: 
     for row in stats.findAll('tr'): 
      stockData.append(row.find('td')) 
      j += 1 
     except AttributeError: 
      print "Table handling error in HTML" 
    k=0 
    for cell in stockData: 
     #clean up text 
     dataline = stockData[k] 
     lineOfData = lineOfData + " " + str(dataline) 
     k += 1 
    g = str(timestamp) + " " + str(ur)+ ' ' + str(lineOfData) + ' ' + ("\n\n\n")  
    myfile.write(g) 
    print (ur + "\n") 
    del stockData[:] 
    lineOfData = "" 
    dataline = "" 
    stats = None 
    page = None 
    soup = None 
    i += 1 

threadlist = [] 

for u in newsymbolslist: 
    t = Thread(target = th, args = (u,)) 
    t.start() 
    threadlist.append(t) 

for b in threadlist: 
    b.join()enter code here 
+1

你在'newsymbolslist'里有多少物品? – csl

+0

约2,700所有纽约证券交易所代码 – Jesse

+3

那么您是否会同时启动2,700个线程? –

回答

2

您启动的每个线程都有一个线程堆栈大小,在Linux系统中(默认为 )为8kb,因此线程所需的内存总数将超过20GB。

您可以使用一个线程池,例如10个线程;当其中一个 已完成工作时,它将执行另一项任务。

但是:一般来说,运行比CPU核心更多的线程是无稽之谈。所以我的 建议是停止使用线程。您可以使用库如gevent到 完全相同的事情,而不使用OS级别的线程。

约GEVENT的好处是猴子修补:你能告诉gevent 改变Python标准库的行为,这会变成你的 线程注入“greenlet”对象透明(见gevent文档 有详细介绍) 。 gevent提议的并发性类型为 ,特别适合密集型I/O。

在你的代码,只需添加下面的开头:

from gevent import monkey; monkey.patch_all() 

你不能有超过1024个文件描述符的同时 Linux系统在默认情况下开启(见ulimit -n)等等如果您希望同时打开2700个文件描述符,则必须增加 此限制。

+0

谢谢!我安装了gevent并按建议运行。它改进了这个程序,它比我最初编码的程序更加深入到列表中。尽管它仍然没有记忆,并且冻结了。我一直在浏览gevent文件,看看我是否可以改变它来阻止它。 – Jesse

+0

你需要明白什么是进食记忆。你是否正确地释放资源? – mguijarr

+0

我不这么认为。任何具体的教程或例子,可以帮助我做到这一点?我一直在通过这个来弄清楚如何使用gevent。 http://doc.scrapy.org/en/0.24/intro/tutorial.html#intro-tutorial – Jesse

0

不要重新发明轮子和使用Scrapy web-scraping framework

Scrapy为抓取网站的应用程序框架和 提取结构化数据,其可用于广泛的 有用的应用,如数据挖掘,信息处理或历史档案。

想想吧 - 可扩展性/并行化/性能问题是帮你解决了 - 你真的要继续在深入Thread S IN蟒蛇精彩的世界,让你的代码气味可疑,击中CPU和内存限制,处理冲突以及最终使您的代码无法调试和维护 - 而不是专注于提取和收集数据?而且,即使在gevent我怀疑你的最终代码将以任何方式更简单和可读,就像你将基于Scrapy实现的一样。为什么不使用被大量用户测试和使用的工具被证明是有史以来在网页抓取python世界中创建的最佳工具?

这里是一个工作蜘蛛刮擦以类似的方式引号:

from scrapy.spider import Spider 
from scrapy.item import Item, Field 
from scrapy.http import Request 


class BloombergItem(Item): 
    ur = Field() 
    parameter = Field() 
    value = Field() 


class BloombergSpider(Spider): 
    name = 'bloomberg' 
    allowed_domains = ['www.bloomberg.com'] 

    def start_requests(self): 
     with open("stocks.txt") as f: 
      for ur in f: 
       yield Request("http://www.bloomberg.com/quote/%s:US" % ur) 

    def parse(self, response): 
     for parameter in response.css('table.key_stat_data tr'): 
      item = BloombergItem() 
      item['ur'] = response.xpath('//title/text()').extract()[0].split(':')[0] 
      item['parameter'] = parameter.xpath('th/text()').extract()[0] 
      item['value'] = parameter.xpath('td/text()').extract()[0] 
      yield item 

如果stocks.txt内容是:

AAPL 

蜘蛛将输出(例如,如果你会选择输出它在JSON中):

[ 
    { 
    "parameter": "Current P/E Ratio (ttm)", 
    "value": "16.6091", 
    "ur": "AAPL" 
    }, 
    { 
    "parameter": "Estimated P/E(09/2015)", 
    "value": "13.6668", 
    "ur": "AAPL" 
    }, 
    { 
    "parameter": "Relative P/E vs.", 
    "value": "0.9439", 
    "ur": "AAPL" 
    }, 
    ... 
] 

Scrapy开始的好地方是Scrapy Tutorial