【问题标题】:Improve Python scraping code with multithreading使用多线程改进 Python 抓取代码
【发布时间】:2018-02-26 09:41:28
【问题描述】:

我正在使用 urllib2、bsoup、csv...(Python 2.7)编写一个简单的 python 爬虫 我有一个 .csv 文件,其中存储了需要抓取的 url 链接。

从下面的代码中,我正在从链接中抓取特定数字,在该链接中它可以从网站上找到最多一个参与者,并且crawl(url) 函数像整个代码一样正常工作。

from bs4 import BeautifulSoup
import json, csv, urllib2, urllib, re, time, lxml

def crawl(url):
    request = urllib2.Request(url, headers={"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36"})
    response = urllib2.urlopen(request)
    readd = response.read()

    soup = BeautifulSoup(readd, "lxml")
    response.close()
    maxx = 0
    if (soup.find("div", attrs={"class" : "attendees-placeholder placeholder"})):
        exists = soup.find("div", attrs={"class" : "attendees-placeholder placeholder"})
        nmb = exists.find("ul", "user-list")
        numbe = nmb.find_all("li")
        number = len(numbe)
        if (number > maxx):
            maxx = number
    else:
        number = 0

    print maxx



urls = csv.reader(open('all_links_2017.csv'))


for url in urls:
    crawl(url[0])

同时,它太慢了,因为我有大约 100000 个网址。 我尝试了许多多线程示例,但这不是我所期望的。 有什么办法可以改进这段代码,让它运行得更快吗? (即多线程、池...)

【问题讨论】:

    标签: python multithreading csv web-scraping beautifulsoup


    【解决方案1】:

    你试过了吗?:

    import threading
    
    def crawl(url, sem):
        # Semaphore grabs a thread
        sem.acquire(blocking=False)
        # Your code here
        .
        .
        .
        # All the work is done (i.e. after print maxx)
        sem.release() 
    
    sem = threading.Semaphore(4)
    threads = [threading.Thread(target=crawl, args=(url, sem, )) for url in urls]
    
    for thread in threads:
        thread.start()
    

    编辑:首先将for 更改为列表理解。

    编辑:添加threading.Semaphore() 限制方法。信号量是一个限制器(本质上是线程计数器),用于跟踪并发运行的线程数。在这种情况下,该值在任何给定时间设置为最多 4 个线程。如果您选择使用BoundedSemaphore(),这也可以与with 上下文管理器一起使用。

    【讨论】:

    • 它自动给我错误:Traceback(最近一次调用最后一次):文件“C:/Users/urosv/Desktop/Conferences project - 30/thread_test.py”,第 32 行,在 thread.start() 错误:无法启动新线程
    • 这个编辑工作完美,唯一的问题是远程服务器因为检测到机器人而阻止连接,有什么办法可以避免吗?
    • @RolandSmith 我们不知道服务器的安全级别。我每天并行发送超过 12 组 20K 查询。我与之交互的服务器不够智能,无法检测 OP 遇到的那种检测。
    • @U.J.V.请参阅我的更新显示使用 threading.Semaphore() 方法。它限制了任何时候执行crawl()的活动线程数。
    【解决方案2】:

    使用multiprocessing.Pool。将 crawl 更改为 return maxx 而不是打印它。然后使用multiprocessing.Pool.imap_unordered 方法。

    p = multiprocessing.Pool()
    urls = csv.reader(open('all_links_2017.csv'))
    for value in p.imap_unordered(crawl, [u[0] for u in urls]):
        print(value)
    

    默认情况下,这将创建与 CPU 内核数量一样多的工作进程。

    【讨论】:

    • 多处理对于简单的 IO 来说似乎很繁重,from multiprocessing.dummy import Pool 还在使用线程怎么样?
    • 鉴于大量使用 'soup,线程很可能会遇到 GIL 问题。由于 parent 和 worker 之间的数据流非常少,因此适当的 Pool 似乎是合适的。
    • @RolandSmith 我更改了 crawl 的返回值,将代码导入为你的,但它不打印任何内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    相关资源
    最近更新 更多