0

私はWebスクレーパーを書いています。私は治療をしたことがありましたが、練習できるように、最初からそれを書くことに決めました。リクエストとBeautifulSoupを使用したPythonマルチスレッド

リクエストとBeautifulSoupを使用して正常に動作するスクレーパーを作成しました。それは約135ページをナビゲートし、それぞれに12個のアイテムを持ち、リンクをつかんでリンク先から情報を取得します。最後にすべてをCSVファイルに書き込む。それは文字列をつかむだけで、イメージやそのようなものは何もダウンロードされません。

問題がありますか?それはかなり遅いです。時間135が約11分になるように、1ページの内容からすべてを取得するのに約5秒かかります。

私の質問はどのように私のコードでスレッド化を実装してデータの高速化を実現するかということです。

import requests 
from bs4 import BeautifulSoup 
import re 
import csv 


def get_actor_dict_from_html(url, html): 
    soup = BeautifulSoup(html, "html.parser") 

    #There must be a better way to handle this, but let's assign a NULL value to all upcoming variables. 
    profileName = profileImage = profileHeight = profileWeight = 'NULL' 

    #Let's get the name and image.. 
    profileName = str.strip(soup.find('h1').get_text()) 
    profileImage = "http://images.host.com/actors/" + re.findall(r'\d+', url)[0] + "/actor-large.jpg" 

    #Now the rest of the stuff.. 
    try: 
     profileHeight = soup.find('a', {"title": "Height"}).get_text() 
    except: 
     pass 
    try: 
     profileWeight = soup.find('a', {"title": "Weight"}).get_text() 
    except: 
     pass 

    return { 
     'Name': profileName, 
     'ImageUrl': profileImage, 
     'Height': profileHeight, 
     'Weight': profileWeight, 
     } 


def lotta_downloads(): 
    output = open("/tmp/export.csv", 'w', newline='') 
    wr = csv.DictWriter(output, ['Name','ImageUrl','Height','Weight'], delimiter=',') 
    wr.writeheader() 

    for i in range(135): 
     url = "http://www.host.com/actors/all-actors/name/{}/".format(i) 
     response = requests.get(url) 
     html = response.content 
     soup = BeautifulSoup(html, "html.parser") 
     links = soup.find_all("div", { "class" : "card-image" }) 

     for a in links: 
      for url in a.find_all('a'): 
       url = "http://www.host.com" + url['href'] 
       print(url) 
       response = requests.get(url) 
       html = response.content 
       actor_dict = get_actor_dict_from_html(url, html) 
       wr.writerow(actor_dict) 
    print('All Done!') 

if __name__ == "__main__": 
    lotta_downloads() 

ありがとう:

は、ここでは、コードです!

+0

をお持ちの場合は通常、あなたが車輪の再発明と 'Scrapy'のWebフレームワークのようなものを使用しない方が良いのだのpython-geventをインストールする必要があります

。 – alecxe

答えて

0

geventライブラリを使用してみませんか?

geventライブラリには、monkey patchがあり、非ブロック機能にブロック機能があります。

wait timeリクエストが多すぎると遅くなることがあります。

私はノンブロッキング機能としてリクエストをするとプログラムが速くなると思います。

import gevent 
from gevent import monkey; monkey.patch_all() # Fix import code 
import reqeusts 

actor_dict_list = [] 

def worker(url): 
    content = requests.get(url).content 
    bs4.BeautifulSoup(content) 
    links = soup.find_all('div', {'class': 'card-image'}) 

    for a in links: 
     for url in a.find_all('a'): 
      response = requests.get(url) # You can also use gevent spawn function on this line 
      ... 
      actor_dict_list.append(get_actor_dict_from_html(url, html)) # Because of preventing race condition 

output = open("/tmp/export.csv", "w", newline='') 
wr = csv.DictWriter(output, ['Name', 'ImageUrl', 'Height', 'Weight'], delimiter=',') 
wr.writeheader() 

urls = ["http://www.host.com/actors/all-actors/name/{}/".format(i) for i in range(135)] 
jobs = [gevent.spawn(worker, url) for url in urls] 
gevent.joinall(jobs) 
for i in actor_dict_list: 
    wr.writerow(actor_dict) 

公共geventドキュメント:doc

P.S.のpython 2.7.10 例で

あなたがUbuntuのOS

sudo apt-get install python-gevent

+1

私はこのコードをどこに配置できるのか分かりませんでした。それは機能内の機能でなければならないのでしょうか? (lotta_downloads)? – kokozz

+0

ああ、申し訳ありません。私の責任です。コードをもう一度見てください。私はそれを修正しました。 – yumere

関連する問題