使用BeautifulSoup进行多处理以改善Wikipedia抓取

我正在使用BeautifulSoup从一堆Wikipedia页面上抓取一些基本信息。该程序运行,但是很慢(650页大约20分钟)。我正在尝试使用多处理来加速此过程,但是它没有按预期工作。它要么似乎被拖延了,什么也没做,要么只是刮擦了每个页面名称的首字母。

我正在使用的抓取代码是:

#dict where key is person's name and value is proper wikipedia url formatting
all_wikis = { 'Adam Ferrara': 'Adam_Ferrara','Adam Hartle': 'Adam_Hartle','Adam Ray': 'Adam_Ray_(comedian)','Adam Sandler': 'Adam_Sandler','Adele Givens': 'Adele_Givens'}
bios = {}
def scrape(dictionary):
    for key in dictionary:
        #search each page
        page = requests.get(("https://en.wikipedia.org/wiki/" + str(key)))
        data = page.text
        soup = BeautifulSoup(data,"html.parser")
        #get data
        try:
            bday = soup.find('span',attrs={'class' : 'bday'}).text
        except:
            bday = 'Birthday Unknown'
        try:
            birthplace = soup.find('div',attrs={'class' : 'birthplace'}).text
        except:
            birthplace = 'Birthplace Unknown'
        try:
            death_date = (soup.find('span',attrs={'style' : "display:none"}).text
                                                                            .replace("(","")
                                                                            .replace(")",""))
            living_status = 'Deceased'
        except:
            living_status = 'Alive'
        try:
            summary = wikipedia.summary(dictionary[key].replace("_"," "))
        except:
            summary = "No Summary"
        bios[key] = {}
        bios[key]['birthday'] = bday
        bios[key]['home_town'] = birthplace
        bios[key]['summary'] = summary
        bios[key]['living_status'] = living_status
        bios[key]['passed_away'] = death_date

我尝试使用下面的代码在脚本末尾添加处理功能,但它不起作用或仅提取每个页面的首字母(例如,如果我要搜索的页面是李小龙,而是将维基百科页面上的字母B拉起来,然后抛出一堆错误)。

from multiprocessing import Pool,cpu_count

if __name__ == '__main__':
    pool = Pool(cpu_count())
    results = pool.map(func=scrape,iterable=all_wiki)
    pool.close()
    pool.join()

是否有更好的方法来构造脚本以进行多处理?

a469096355 回答:使用BeautifulSoup进行多处理以改善Wikipedia抓取

这里有几个问题:

  • dictionaryall_wikis字典中的每个字符串键。然后,当您使用for key in dictionary:遍历此字符串时,它将访问该字符串中的每个字符。您的第一个请求是https://en.wikipedia.org/wiki/A,这不是期望的结果。
  • str(key)并不是真正有用,即使dictionary是一个名字。我们需要使用all_wikis[name]查找正确的URL。另外,请避免使用dictionary之类的通用变量。
  • 由于您正在进行多处理,因此bios之类的数据需要共享才能进行操作。最简单的方法就是只使用map函数的返回值,该函数是所有worker函数返回值的汇总。
  • 您的抓取存在逻辑问题。 wikipedia.summary未定义。如果不确定您确切想要的结果,则表示亚当·桑德勒(Adam Sandler)已故。我将把它留给读者练习,因为这个问题主要是关于多处理的。
  • 我不确定在这里多处理是否像多线程一样理想。由于您的进程将被阻止在99%的时间内发出请求,因此我敢打赌,与您拥有的内核数量相比,使用更多的线程(或进程)可以获得更高的效率。当您需要进行CPU限制的工作时,多处理更为合适,在这种情况下不是这样。实际上,Python过程本身将花费很少的时间。我建议通过增加进程(或线程,如果您要进行重构)来增加代码的数量,以测试代码,直到您停止看到改进为止。

这里有一些代码可以帮助您入门。我会按照您的示例进行多处理,并且没有调整网络抓取逻辑。

import requests
from bs4 import BeautifulSoup
from multiprocessing import Pool,cpu_count

all_wikis = {'Adam Ferrara': 'Adam_Ferrara','Adam Hartle': 'Adam_Hartle','Adam Ray': 'Adam_Ray_(comedian)','Adam Sandler': 'Adam_Sandler','Adele Givens': 'Adele_Givens'}

def scrape(name):
    data = requests.get("https://en.wikipedia.org/wiki/" + all_wikis[name]).text
    soup = BeautifulSoup(data,"html.parser")
    bio = {}

    try:
        bio['birthday'] = soup.find('span',attrs={'class': 'bday'}).text
    except:
        bio['birthday'] = 'Birthday Unknown'

    try:
        bio['home_town'] = soup.find('div',attrs={'class': 'birthplace'}).text
    except:
        bio['home_town'] = 'Birthplace Unknown'

    try:
        bio['passed_away'] = (soup.find('span',attrs={'style': "display:none"}).text
                                                                        .replace("(","")
                                                                        .replace(")",""))
        bio['living_status'] = 'Deceased'
    except:
        bio['living_status'] = 'Alive'

    bio['summary'] = "No Summary"
    return name,bio


if __name__ == '__main__':
    pool = Pool(cpu_count())
    bios = dict(pool.map(func=scrape,iterable=all_wikis))
    pool.close()
    pool.join()
    print(bios)
本文链接:https://www.f2er.com/3139871.html

大家都在问