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