2017-01-29 7 views
0

このクローラをPythonで作成しました。ドメインの入力リストに基づいていくつかのパラメータをJSON出力ファイルにダンプします。PythonマルチスレッドHTTPクローラ - プログラムの接続とハングをクローズ

この質問はありません

各スレッドでHTTP接続を閉じる必要がありますか?入力データはca. 500万アイテムそれはレートcaで最初に処理されます。毎秒50回の反復が実行されますが、しばらくしてから1秒に1〜2に落ちるか、ハングします(カーネルメッセージはなく、stdoutにエラーはありません)。これはコードにすることができますか?私はそれを再起動してからソフトウェアが高いレート(毎秒約50反復)で起動するので疑いがあります。以下のコードを改善する方法については、特にスピードとクロールのスループットを向上させるためのヒントもあります。質問で

コード:

import urllib2 
import pprint 
from tqdm import tqdm 

import lxml.html 

from Queue import Queue 

from geoip import geolite2 
import pycountry 

from tld import get_tld 



resfile = open("out.txt",'a') 



concurrent = 200 

def doWork(): 
    while True: 
     url = q.get() 
     status = getStatus(url) 
     doSomethingWithResult(status) 
     q.task_done() 

def getStatus(ourl): 
    try: 
     response = urllib2.urlopen("http://"+ourl) 
     peer = response.fp._sock.fp._sock.getpeername() 
     ip = peer[0] 
     header = response.info() 
     html = response.read() 
     html_element = lxml.html.fromstring(html) 
     generator = html_element.xpath("//meta[@name='generator']/@content") 
     try: 
     match = geolite2.lookup(ip) 
     if match is not None: 
      country= match.country 
      try: 

      c=pycountry.countries.lookup(country) 
      country=c.name 
      except: 
      country="" 

     except: 
     country="" 
     try: 
     res=get_tld("http://www"+ourl, as_object=True) 
     tld=res.suffix 
     except: 
     tld="" 

     try: 
     match = re.search(r'[\w\.-][email protected][\w\.-]+', html) 
     email=match.group(0) 
     except: 
     email="" 

     try: 
      item= generator[0] 
      val = "{ \"Domain\":\"http://"+ourl.rstrip()+"\",\"IP:\""+ip+"\"," + "\"Server\":"+ "\""+str(header.getheader("Server")).replace("None","")+"\",\"PoweredBy\":" + "\""+str(header.getheader("X-Powered-By")).replace("None","")+"\""+",\"MetaGenerator\":\""+item+"\",\"Email\":\""+email+"\",\"Suffix\":\""+tld+"\",\"CountryHosted\":\""+country+"\" }" 
     except: 
      val = "{ \"Domain\":\"http://"+ourl.rstrip()+"\",\"IP:\""+ip+"\"," + "\"Server\":"+ "\""+str(header.getheader("Server")).replace("None","")+"\",\"PoweredBy\":" + "\""+str(header.getheader("X-Powered-By")).replace("None","")+"\""+",\"MetaGenerator\":\"\",\"Email\":\""+email+"\",\"Suffix\":\""+tld+"\",\"CountryHosted\":\""+country+"\" }" 

     return val 
    except Exception as e: 
     #print "error"+str(e) 
     pass 

def doSomethingWithResult(status): 
    if status: 
     resfile.write(str(status)+"\n") 

q = Queue(concurrent * 2) 
for i in range(concurrent): 
    t = Thread(target=doWork) 
    t.daemon = True 
    t.start() 

try: 
    for url in tqdm(open('list.txt')): 
     q.put(url.strip()) 
     status = open("status.txt",'w') 
     status.write(str(url.strip())) 
    q.join() 
except KeyboardInterrupt: 
    sys.exit(1) 

アップデート1:

ソケットを閉じるとのFileDescriptorが、それは良い仕事作るには、いくつかの時間後にはもうハングアップしていないようです。パフォーマンスは自宅のラップトップ上の50 REQS /秒で、VPS

from threading import Thread 
import httplib, sys 
import urllib2 
import pprint 
from tqdm import tqdm 

import lxml.html 

from Queue import Queue 

from geoip import geolite2 
import pycountry 

from tld import get_tld 
import json 



resfile = open("out.txt",'a') 



concurrent = 200 

def doWork(): 
    while True: 
     url = q.get() 
     status = getStatus(url) 
     doSomethingWithResult(status) 
     q.task_done() 

def getStatus(ourl): 
    try: 
     response = urllib2.urlopen("http://"+ourl) 
     realsock = response.fp._sock.fp._sock 
     peer = response.fp._sock.fp._sock.getpeername() 
     ip = peer[0] 
     header = response.info() 
     html = response.read() 
     realsock.close() 
     response.close() 

     html_element = lxml.html.fromstring(html) 
     generator = html_element.xpath("//meta[@name='generator']/@content") 
     try: 
     match = geolite2.lookup(ip) 
     if match is not None: 
      country= match.country 
      try: 

      c=pycountry.countries.lookup(country) 
      country=c.name 
      except: 
      country="" 

     except: 
     country="" 
     try: 
     res=get_tld("http://www"+ourl, as_object=True) 
     tld=res.suffix 
     except: 
     tld="" 

     try: 
     match = re.search(r'[\w\.-][email protected][\w\.-]+', html) 
     email=match.group(0) 
     except: 
     email="" 

     try: 
      item= generator[0] 
      val = "{ \"Domain\":"+json.dumps("http://"+ourl.rstrip())+",\"IP\":\""+ip+"\",\"Server\":"+json.dumps(str(header.getheader("Server")).replace("None",""))+",\"PoweredBy\":" +json.dumps(str(header.getheader("X-Powered-By")).replace("None",""))+",\"MetaGenerator\":"+json.dumps(item)+",\"Email\":"+json.dumps(email)+",\"Suffix\":\""+tld+"\",\"CountryHosted\":\""+country+"\" }" 
     except: 
      val = "{ \"Domain\":"+json.dumps("http://"+ourl.rstrip())+",\"IP\":\""+ip+"\"," + "\"Server\":"+json.dumps(str(header.getheader("Server")).replace("None",""))+",\"PoweredBy\":" +json.dumps(str(header.getheader("X-Powered-By")).replace("None",""))+",\"MetaGenerator\":\"\",\"Email\":"+json.dumps(email)+",\"Suffix\":\""+tld+"\",\"CountryHosted\":\""+country+"\" }" 

     return val 
    except Exception as e: 
     print "error"+str(e) 
     pass 

def doSomethingWithResult(status): 
    if status: 
     resfile.write(str(status)+"\n") 

q = Queue(concurrent * 2) 
for i in range(concurrent): 
    t = Thread(target=doWork) 
    t.daemon = True 
    t.start() 

try: 
    for url in tqdm(open('list.txt')): 
     q.put(url.strip()) 
     status = open("status.txt",'w') 
     status.write(str(url.strip())) 
    q.join() 
except KeyboardInterrupt: 
    sys.exit(1) 

答えて

0

上100のREQ /秒CAハンドルが自動的にゴミ収集になりますが、あなたはあなたがやっている、特にとして、ハンドルを自分で閉じたほうが良いでしょうこれはタイトなループです。

改善のための提案も依頼しました。大きなものはurllib2の使用をやめ、代わりにrequestsを使用することです。

+0

THANKS !!!!私はソケットを閉じてディスクリプタよりも良くなりました。要求に見える.... –

0

クロールレートが低下する理由はたくさんあります。

1.)同じドメインの多くのデータにクロールしないように注意してください。一部のWebサーバーは、IPアドレスごとに1つの接続を並行して実行できるように構成されています。

2.)ブラウザが設定されている場合は、ブラウザのようなランダムなHTTPヘッダー(user-agent、referrer、...)を送信して、Webサーバーのスクレイプ防止を防止してください。

3.)pycurl(MultiCurl)やリクエスト(grequests)のような成熟したhttp(パラレル)ライブラリを使用します。彼らは確かにより速く実行します。

+0

ありがとう!!!私はそれが私の質問にもっと指示されたので、他の答えを選んだ。私は2つの答えを選ぶことができればいいと思います。あなたもとても良いですから。 –

関連する問題