Python爬虫

Python爬虫 知识量:11 - 28 - 71

6.2 多线程爬虫><

单线程爬虫- 6.2.1 -

Python单线程爬虫的实现通常涉及使用Python的内置库或第三方库来发送HTTP请求并解析网页内容。以下是一个简单的示例,展示了如何使用Python的requests和BeautifulSoup库来创建一个单线程爬虫:

import requests  
from bs4 import BeautifulSoup  
  
def crawl_website(url):  
    try:  
        response = requests.get(url)  
        response.raise_for_status()  # 确保请求成功  
        return response.text  
    except requests.RequestException as e:  
        print(f"请求出错: {e}")  
        return None  
  
def parse_html(html):  
    soup = BeautifulSoup(html, 'html.parser')  
    # 在这里编写解析HTML的逻辑,提取所需的数据  
    # 例如,提取所有的链接  
    links = soup.find_all('a')  
    for link in links:  
        print(link.get('href'))  # 打印链接  
  
def main():  
    start_url = 'http://example.com'  # 替换为要爬取的网站地址  
    html = crawl_website(start_url)  
    if html:  
        parse_html(html)  
  
if __name__ == '__main__':  
    main()

在这个示例中,定义了三个函数:crawl_website用于发送HTTP GET请求并返回响应的文本内容;parse_html用于解析HTML并提取所需的数据;main函数是程序的入口点,它调用crawl_website函数获取网页内容,并调用parse_html函数解析和提取数据。

Python多线程- 6.2.2 -

Python多线程可以使用内置的threading模块来实现。多线程允许同时执行多个线程,每个线程可以执行不同的任务。下面是一个简单的Python多线程示例:

import threading  
  
# 定义一个函数作为线程要执行的代码  
def worker():  
    print("Thread {} is running.".format(threading.current_thread().name))  
  
# 创建线程  
thread1 = threading.Thread(target=worker, name="Thread-1")  
thread2 = threading.Thread(target=worker, name="Thread-2")  
  
# 启动线程  
thread1.start()  
thread2.start()  
  
# 等待线程结束  
thread1.join()  
thread2.join()  
  
print("All threads are done.")

在上面的示例中,定义了一个名为worker的函数,它将在每个线程中执行。然后,创建了两个线程thread1和thread2,并将worker函数作为目标传递给它们。通过调用start()方法启动线程,并使用join()方法等待线程完成。最后,打印出"All threads are done."表示所有线程已经完成。

需要注意的是,Python的全局解释器锁(GIL)限制了同一时间只能有一个线程执行Python字节码。这意味着在多核CPU上,Python多线程可能不会充分利用硬件资源。为了更好地利用多核CPU的性能,可以考虑使用进程(使用multiprocessing模块)或异步IO(使用asyncio模块)。

多线程爬虫- 6.2.3 -

Python多线程爬虫可以使用Python的多线程模块threading来实现。下面是一个简单的示例,展示如何使用多线程爬虫来爬取网页内容:

import threading  
import requests  
from bs4 import BeautifulSoup  
  
# 定义一个爬虫函数  
def crawl_website(url):  
    try:  
        response = requests.get(url)  
        response.raise_for_status()  # 确保请求成功  
        return response.text  
    except requests.RequestException as e:  
        print(f"请求出错: {e}")  
        return None  
  
# 定义一个解析函数  
def parse_html(html):  
    soup = BeautifulSoup(html, 'html.parser')  
    # 在这里编写解析HTML的逻辑,提取所需的数据  
    # 例如,提取所有的链接  
    links = soup.find_all('a')  
    for link in links:  
        print(link.get('href'))  # 打印链接  
  
# 定义一个线程类  
class MyThread(threading.Thread):  
    def __init__(self, url):  
        threading.Thread.__init__(self)  
        self.url = url  
    def run(self):  
        html = crawl_website(self.url)  
        if html:  
            parse_html(html)  
  
# 主程序入口  
if __name__ == '__main__':  
    start_url = 'http://example.com'  # 替换为要爬取的网站地址  
    threads = []  # 用于存储线程的列表  
    # 创建多个线程并启动它们  
    for i in range(5):  # 假设要创建5个线程来爬取网页内容  
        thread = MyThread(start_url)  
        threads.append(thread)  
        thread.start()  # 启动线程  
    # 等待所有线程完成  
    for thread in threads:  
        thread.join()  
    print("所有线程已完成")

在上面的示例中,定义了一个MyThread类,它继承自threading.Thread类。在MyThread类的run方法中,调用crawl_website函数来获取网页内容,然后调用parse_html函数来解析和提取所需的数据。在主程序中,创建了多个线程,并将要爬取的网页地址传递给每个线程。然后,启动线程并使用join方法等待所有线程完成。最后,打印出"所有线程已完成"表示所有线程已经完成。

使用Queue的多线程爬虫- 6.2.4 -

使用Python的queue模块与多线程爬虫结合,可以更有效地管理线程之间的任务分配和数据传递。下面是一个使用queue模块的示例:

import threading  
import requests  
from bs4 import BeautifulSoup  
import queue  
  
# 定义一个爬虫函数  
def crawl_website(q, url):  
    while not q.empty():  # 从队列中获取任务  
        next_url = q.get()  
        try:  
            response = requests.get(next_url)  
            response.raise_for_status()  # 确保请求成功  
            parse_html(response.text)  # 解析HTML并提取所需数据  
        except requests.RequestException as e:  
            print(f"请求出错: {e}")  
  
# 定义一个解析函数  
def parse_html(html):  
    soup = BeautifulSoup(html, 'html.parser')  
    # 在这里编写解析HTML的逻辑,提取所需的数据  
    # 例如,提取所有的链接  
    links = soup.find_all('a')  
    for link in links:  
        print(link.get('href'))  # 打印链接  
  
# 主程序入口  
if __name__ == '__main__':  
    start_url = 'http://example.com'  # 替换为要爬取的网站地址  
    q = queue.Queue()  # 创建一个队列对象  
    threads = []  # 用于存储线程的列表  
    # 将起始URL放入队列中  
    q.put(start_url)  
    # 创建多个线程并启动它们来处理队列中的任务  
    for i in range(5):  # 假设要创建5个线程来爬取网页内容  
        thread = threading.Thread(target=crawl_website, args=(q,))  
        threads.append(thread)  
        thread.start()  # 启动线程  
    # 等待所有线程完成  
    for thread in threads:  
        thread.join()  
    print("所有线程已完成")

在上面的示例中,使用queue.Queue()创建了一个队列对象q,并将起始URL放入队列中。然后,创建了多个线程,并将队列对象作为参数传递给crawl_website函数。在crawl_website函数中,使用q.get()从队列中获取任务,并执行相应的爬取操作。这样,每个线程都可以从队列中获取任务并独立执行,从而实现多线程爬虫的效果。