python - 无法让脚本以自定义方式使用 concurrent.futures 填充结果

标签 python python-3.x web-scraping concurrent.futures

我在 python 中创建了一个脚本来从站点的 landing page 中抓取用户名和它的标题是inner page .我正在尝试使用 concurrent.futures 库来执行并行任务。我知道如何在下面的脚本中使用 executor.submit(),所以我不想那样做。我想使用我已经在以下脚本中定义(可能以错误的方式)的 executor.map()

我试过:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import concurrent.futures as futures

URL = "https://stackoverflow.com/questions/tagged/web-scraping"
base = "https://stackoverflow.com"

def get_links(s,url):
    res = s.get(url)
    soup = BeautifulSoup(res.text,"lxml")
    for item in soup.select(".summary"):
        user_name = item.select_one(".user-details > a").get_text(strip=True)
        post_link = urljoin(base,item.select_one(".question-hyperlink").get("href"))
        yield s,user_name,post_link

def fetch(s,name,url):
    res = s.get(url)
    soup = BeautifulSoup(res.text,"lxml")
    title = soup.select_one("h1[itemprop='name'] > a").text
    return name,title

if __name__ == '__main__':
    with requests.Session() as s:
        with futures.ThreadPoolExecutor(max_workers=5) as executor:
            link_list = [url for url in get_links(s,URL)]
            for result in executor.map(fetch, *link_list):
                print(result)

按原样运行上述脚本时出现以下错误:

TypeError: fetch() takes 3 positional arguments but 50 were given

如果我运行修改此部分的脚本 link_list = [url for url in get_links(s,URL)][0],我会收到以下错误:

TypeError: zip argument #1 must support iteration

How can I successfully execute the above script keeping the existing design intact?

最佳答案

因为 fetch 有 3 个参数(s、name、url),你需要传递 3 个 iterablesexecutor.map() .

当你这样做时:

executor.map(fetch, *link_list)

link_list 解压 49 个左右的元组,每个元组包含 3 个元素(Session 对象、用户名和 url)。这不是你想要的。

您需要做的是首先将 link_list 转换为 3 个独立的可迭代对象(一个用于 Session 对象,另一个用于用户名,一个用于 url)。您可以使用 zip() 和解包运算符两次,而不是手动执行此操作,如下所示:

            for result in executor.map(fetch, *zip(*link_list)):

此外,当我测试您的代码时,get_links 中出现异常:

    user_name = item.select_one(".user-details > a").get_text(strip=True)

AttributeError: 'NoneType' object has no attribute 'get_text'

item.select_one 返回了 None,这显然没有 get_text() 方法,所以我只是尝试了一下/except block ,捕获 AttributeError 并继续循环。

另请注意,Requests 的 Session 类不是线程安全的。 幸运的是,脚本在我运行时返回了正常的响应,但如果您希望脚本可靠,则需要解决这个问题。由于线程本地数据,第二个链接中的注释显示了如何为每个线程使用一个 Session 实例。见:

关于python - 无法让脚本以自定义方式使用 concurrent.futures 填充结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61475708/

相关文章:

python - 如何修复 "E: Package ' libatlas-dev'没有安装候选者“在为 Scikit 学习安装 Scipy 时?

Python RoboBrowser SSL 错误 : bad handshake: SysCallError(104, 'ECONNRESET' )

python - 获取特定于其中元素的子列表的索引

python - 如何在维基百科页面中抓取一页的多个表格?

python - 提取 Twitter 帐户描述 抓取

python - 在小部件 WxPython 之间添加空间

python - 从循环内的 a.href 获取数据

python - 使用 Python 打开 Word 文档

python - 更改列表的 boolean 列表的某个索引也会更改其他索引

javascript - 如何使用 R 从国家文件馆 (archives.gov) 中抓取目录系列中的所有文件