【问题标题】:How to accelerate Webscraping using the combination of Request and BeautifulSoup in Python?如何在 Python 中结合使用 Request 和 BeautifulSoup 来加速 Webscraping?
【发布时间】:2020-11-01 16:10:32
【问题描述】:

目标是使用BeautifulSoup 抓取多个pages,其输入来自requests.get 模块。

步骤如下:

首先使用requests加载html

page = requests.get('https://oatd.org/oatd/' + url_to_pass)

然后,使用以下定义抓取html 内容:

def get_each_page(page_soup):
    return dict(paper_author=page_soup.find(attrs={"itemprop": "name"}).text,
                paper_title=page_soup.find(attrs={"itemprop": "name"}).text)

比如说,我们有一百个唯一的url要抓取 ['record?record=handle\:11012\%2F16478&q=eeg'] * 100,整个过程可以通过下面的代码完成:

import requests
from bs4 import BeautifulSoup as Soup

def get_each_page(page_soup):
    return dict(paper_author=page_soup.find(attrs={"itemprop": "name"}).text,
                paper_title=page_soup.find(attrs={"itemprop": "name"}).text)

list_of_url = ['record?record=handle\:11012\%2F16478&q=eeg'] * 100 # In practice, there will be 100 diffrent unique sub-href. But for illustration purpose, we purposely duplicate the url
all_website_scrape = []
for url_to_pass in list_of_url:

    page = requests.get('https://oatd.org/oatd/' + url_to_pass)
    if page.status_code == 200:
        all_website_scrape.append(get_each_page(Soup(page.text, 'html.parser')))

但是,每个 url 都被请求并一次抓取一个,因此原则上很耗时。

我不知道是否有其他方法可以提高我不知道的上述代码的性能?

【问题讨论】:

标签: python web-scraping beautifulsoup python-requests


【解决方案1】:

您也许可以使用线程模块。 您可以使脚本多线程并运行得更快。 https://docs.python.org/3/library/threading.html

但如果你愿意改变主意,我推荐scrapy

【讨论】:

  • 感谢您的建议。但就目前而言,我的整体框架基于 BSoup
【解决方案2】:

realpython.com 有一篇很好的文章,介绍了如何通过并发加速 Python 脚本。

https://realpython.com/python-concurrency/

使用他们的线程示例,您可以设置执行多个线程的工作线程数,从而增加您一次可以发出的请求数。

    from bs4 import BeautifulSoup as Soup
    import concurrent.futures
    import requests
    import threading
    import time
    
    def get_each_page(page_soup):
        return dict(paper_author=page_soup.find(attrs={"itemprop": "name"}).text,
                    paper_title=page_soup.find(attrs={"itemprop": "name"}).text)
    
    def get_session():
        if not hasattr(thread_local, "session"):
            thread_local.session = requests.Session()
        return thread_local.session
    
    def download_site(url_to_pass):
        session = get_session()
        page = session.get('https://oatd.org/oatd/' + url_to_pass, timeout=10)
        print(f"{page.status_code}: {page.reason}")
        if page.status_code == 200:
            all_website_scrape.append(get_each_page(Soup(page.text, 'html.parser')))
    
    def download_all_sites(sites):
        with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
            executor.map(download_site, sites)
    
    if __name__ == "__main__":
        list_of_url = ['record?record=handle\:11012\%2F16478&q=eeg'] * 100  # In practice, there will be 100 diffrent unique sub-href. But for illustration purpose, we purposely duplicate the url
        all_website_scrape = []
        thread_local = threading.local()
        start_time = time.time()
        download_all_sites(list_of_url)
        duration = time.time() - start_time
        print(f"Downloaded {len(all_website_scrape)} in {duration} seconds")

【讨论】:

  • 太棒了,感谢您的链接和代码。但是,我应该注意,建议的方法可能会导致website 拒绝request,从错误403: Forbidden 可以看出
  • 不用担心 :) 是的,我也看到了。网站很可能拒绝来自同一 IP 地址的多个同时请求。我用不同的站点测试了相同的代码,我没有遇到任何被拒绝的请求。
猜你喜欢
  • 2017-05-06
  • 2021-11-01
  • 2023-03-05
  • 2018-06-11
  • 2017-05-24
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 1970-01-01
相关资源
最近更新 更多