webscraping两个网站的最佳方法Python 3

时间:2017-05-17 16:17:49

标签: multithreading python-3.x web-scraping beautifulsoup

我希望从两个网站获取信息并在实时'实时显示在控制台中。

要从网站获取信息,我使用的是BeautifulSoup 4.我读过,抓网站的瓶颈是连接或网站本身。所以我想使用多线程,因此可以同时完成读取操作。以下是我的代码:

import urllib
from bs4 import BeautifulSoup
import threading
import time




link_website_one = 'http://www.website1.com'
link_website_one = 'http://www.website2.com'



def request_url(url):
    user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36'
    header = { 'User-Agent' : user_agent }

    req = urllib.request.Request(url, headers=header)
    try:
        response = urllib.request.urlopen(req)
        return response
    except urllib.error.HTTPError as e:
        print('The server couldn\'t fulfill the request.')
        print(e.code,': ', e.reason)
        return None
    except urllib.error.URLError as e:
        print('We failed to reach a server.')
        print(e.code,': ', e.reason)
        return None


def new_entry(website, lis, arr, a_id):
    if website == 0 :
        info1 = arr.find()
        info2 = arr.find('div', {'class' : '1'}).find('span', {'class' : '7'}).get_text().strip()
        info3 = arr.find('span', {'class' : '2'}).get_text().strip()
        info4 = arr.find('span', {'class' : '3'}).get_text().strip()
        info5 = arr.find('span', {'class' : '4'}).get_text().strip()
        info6 = arr.find('div', {'class' : '5'}).get_text().strip() 
        lis.append({'info1' : info1, 'info2' : info2, 'info3' : info3, 'info4' : info4, 'info5' : info5, 'info6' : info6})
    elif website == 1 :
        info1 = a_id
        info2 = arr.find('span', {'class' : '8'}).get_text()
        info3 = arr.find('div', {'class' : '9'}).get_text()
        info4 = arr.find_all('div', {'class' : '10'})[0].get_text()
        info5 = arr.find_all('div', {'class' : '10'})[1].get_text()
        info6 = arr.a["href"]
        lis.append({'info1' : info1, 'info2' : info2, 'info3' : info3, 'info4' : info4, 'info5' : info5, 'info6' : info6})


class AsyncSearch(threading.Thread):

    def __init__(self, website, iter_rounds, delay_time):
        threading.Thread.__init__(self)
        self.website = website
        self.iter_rounds = iter_rounds
        self.delay_time = delay_time

    def run(self):
        if self.website == 0:
            for z in range(self.iter_rounds):
                req_1 = request_url(link_1) 
                content_1 =req_1.read()
                soup_1 = BeautifulSoup(content_1, 'lxml') 
                arr_1 = soup_1.find_all('div', {'class' : 'special_class'}) 
                for x in range(len(arr_1)):
                    id_as = int(arr_1[x].find('class123')['class2345'].split(',')[0].split('"')[3].strip())
                    if id_as not in found_ids_1: 
                        found_ids_1.add(id_as)
                        new_entry(0, all_entries_1, arr_1[x], id_as)
                    #else:
                    #    break
                req_1.close()
                time.sleep(self.delay_time)

        elif self.website == 1:
            for z in range(self.iter_rounds):
                req_2 = request_url(link)
                content_2 =req_2.read()
                soup_2 = BeautifulSoup(content_2, 'lxml')
                arr_2 = soup_2.find_all('div', {'class' : 'class445'})
                for x in range(len(arr_2)):
                    if arr_2[x].a['oid'] not in found_ids_2:
                        #print('Mobile: ',test[x].a[Inserat_ID])
                        found_ids_2.add(arr_2[x].a['oid'])
                        new_entry(1, all_entries_1, arr_2[x], arr_2[x].a['oid'])
                    #else:
                    #    break
                req.close()
                time.sleep(self.delay_time)


all_entries_1=[]
all_entries_2=[]
found_ids_1 = set()
found_ids_2 = set()

website1 = AsyncSearch(0,10,1)
website2 = AsyncSearch(1,10,1)


website1.start()
website2.start()    

website1.join()
website2.join()

创建了两个列表中的第一个(all_entries 1/2)和两个集合(found_ids 1/2)。

我正在抓取的网站每页提供20个广告,其中包含独特的ID。使用new_entry方法,您可以说出您想要的网站,应该在哪个列表中附加新条目,哪个数组包含beautifulsoup以及要添加的广告的ID。

现在,对于mutlithreading,我创建了一个AsyncSearch类,您可以在其中选择网站,选择请求的迭代次数以及等待下一个请求的时间。

两套found_ids 1/2都在那里,所以你不要在all_entries列表中多次追加广告。

现在问题。这段代码有效。

但是:如果delay_time = 1且迭代次数= 10,则需要20秒才能完成。有没有更快的方法来解决这个问题?网站1的.read()持续时间介于0.12和0.17秒之间,网站2介于0.03和0.10秒之间。

如果我说任何不可理解的事情,请问。

0 个答案:

没有答案