requests-html多线程爬取实战:5行代码榨干系统性能

requests-html多线程爬取实战:5行代码榨干系统性能

【免费下载链接】requests-html Pythonic HTML Parsing for Humans™ 【免费下载链接】requests-html 项目地址: https://gitcode.com/gh_mirrors/re/requests-html

你还在为单线程爬虫龟速发愁?面对海量网页数据,普通爬虫常常让CPU和网络资源处于闲置状态。本文将带你用requests-html构建高效多线程爬虫,5分钟学会如何充分利用系统资源,爬取效率提升10倍!读完本文你将掌握:

  • 多线程爬取基础实现
  • 线程池资源控制技巧
  • 实战案例:批量抓取网页标题
  • 性能优化与反爬策略

为什么选择requests-html

requests-html是一个为人类设计的Pythonic HTML解析库,正如其项目描述"Pythonic HTML Parsing for Humans™"所言,它将复杂的网页解析变得简单直观。相比传统的BeautifulSoup+requests组合,它内置了以下优势:

  • 全JavaScript支持:通过Pyppeteer集成Chromium,轻松处理动态渲染内容
  • 智能选择器:同时支持CSS选择器和XPath,满足不同场景需求
  • 会话管理:内置Session对象,自动处理cookies和连接池
  • 编码自动检测:无需手动指定网页编码格式

项目核心代码位于requests_html.py,官方使用文档可参考README.rst

多线程爬取基础

单线程vs多线程对比

模式优势劣势适用场景
单线程简单直观、资源消耗低效率低下、资源利用率低少量页面爬取
多线程并行处理、效率高实现复杂、需控制并发数大量页面爬取

多线程爬取的核心在于利用Python的concurrent.futures模块,通过线程池管理多个爬取任务。requests-html本身虽未直接提供多线程支持,但可与ThreadPoolExecutor完美结合,实现高效并发爬取。

快速上手:安装与基础配置

首先通过pipenv安装requests-html:

$ pipenv install requests-html
✨🍰✨

安装文件定义在Pipfile中,确保你的Python版本为3.6及以上。

基础使用示例:

from requests_html import HTMLSession

# 创建会话对象
session = HTMLSession()

# 发送请求
response = session.get('https://example.com')

# 解析标题
title = response.html.find('title', first=True).text
print(title)  # 输出: Example Domain

实战案例:多线程批量爬取网页标题

5行核心代码实现

下面是一个多线程爬取网页标题的完整示例,通过ThreadPoolExecutor实现并发控制:

from requests_html import HTMLSession
from concurrent.futures import ThreadPoolExecutor

# 创建会话对象
session = HTMLSession()

# 待爬取的URL列表
urls = [
    'https://example.com',
    'https://github.com',
    'https://python.org',
    # 可添加更多URL...
]

# 定义爬取函数
def fetch_title(url):
    try:
        response = session.get(url, timeout=10)
        # 使用CSS选择器获取标题
        title_element = response.html.find('title', first=True)
        return title_element.text if title_element else 'No title'
    except Exception as e:
        return f"Error: {str(e)}"

# 使用线程池执行爬取任务
with ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(fetch_title, urls))

# 打印结果
for url, title in zip(urls, results):
    print(f"{url}: {title}")

代码解析

  1. 会话管理:创建全局HTMLSession对象,避免重复创建连接开销
  2. 线程池配置:通过max_workers参数控制并发数,一般设置为CPU核心数*2
  3. 异常处理:捕获请求和解析过程中的异常,确保线程池稳定运行
  4. 选择器使用:使用response.html.find()方法和CSS选择器提取标题

线程池资源控制策略

动态调整并发数

爬取效率并非一味提高并发数就能提升,需要根据目标网站承受能力和本地资源情况动态调整:

import os
import math

# 根据CPU核心数计算最佳并发数
cpu_count = os.cpu_count()
# 通常设置为CPU核心数的2-4倍
optimal_workers = cpu_count * 3

# 对于不同网站设置不同并发数
def get_worker_count(domain):
    # 对反爬严格的网站降低并发
    strict_domains = ['github.com', 'google.com']
    if any(d in domain for d in strict_domains):
        return max(1, cpu_count)
    return optimal_workers

任务队列与优先级

对于大量URL爬取,可使用队列实现任务优先级管理:

from queue import PriorityQueue

# 创建优先级队列
queue = PriorityQueue()

# 添加任务到队列 (优先级, URL)
urls_with_priority = [
    (1, 'https://python.org'),    # 高优先级
    (2, 'https://example.com'),   # 中优先级
    (3, 'https://github.com'),    # 低优先级
]

for priority, url in urls_with_priority:
    queue.put((priority, url))

# 从队列获取任务并处理
results = []
with ThreadPoolExecutor(max_workers=optimal_workers) as executor:
    while not queue.empty():
        priority, url = queue.get()
        results.append(executor.submit(fetch_title, url))
    
    # 获取结果
    for future in results:
        print(future.result())

高级技巧:结合异步支持

requests-html本身提供了AsyncHTMLSession支持异步请求,可与多线程结合使用,进一步提升性能:

from requests_html import AsyncHTMLSession
import asyncio

async def async_fetch_title(url):
    session = AsyncHTMLSession()
    try:
        response = await session.get(url, timeout=10)
        title_element = response.html.find('title', first=True)
        await session.close()
        return title_element.text if title_element else 'No title'
    except Exception as e:
        return f"Error: {str(e)}"

# 在多线程中运行异步任务
def run_async_task(url):
    return asyncio.run(async_fetch_title(url))

# 使用线程池执行异步任务
with ThreadPoolExecutor(max_workers=optimal_workers) as executor:
    results = list(executor.map(run_async_task, urls))

这种混合模式特别适合爬取需要JavaScript渲染的动态网页,相关实现可参考requests_html.py中HTML类的arender方法。

性能优化与反爬策略

合理设置请求头

模拟浏览器请求,避免被目标网站屏蔽:

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
}

# 在get请求中添加headers参数
response = session.get(url, headers=headers, timeout=10)

随机延迟控制

通过随机延迟模拟人类浏览行为,降低被反爬系统检测的风险:

import random
import time

def fetch_title_with_delay(url):
    # 添加随机延迟,范围0.5-2秒
    time.sleep(random.uniform(0.5, 2))
    return fetch_title(url)

结果缓存机制

对重复请求进行缓存,避免无效网络请求:

from functools import lru_cache

# 注意:lru_cache不支持带Session对象的函数,需单独提取URL处理逻辑
@lru_cache(maxsize=100)
def get_cached_title(url):
    # 这里实现纯URL处理逻辑,不带Session参数
    pass

总结与展望

通过本文介绍的多线程爬取方法,你已经掌握了如何充分利用系统资源提升爬取效率。关键要点包括:

  1. 使用ThreadPoolExecutor控制并发线程数
  2. 合理设置max_workers参数,平衡效率与资源消耗
  3. 结合requests-html的强大选择器功能解析网页
  4. 实施反爬策略,确保爬虫稳定运行

项目测试文件tests/test_requests_html.py中包含了更多API使用示例,你可以参考这些测试用例进一步扩展爬虫功能。

未来你还可以探索分布式爬取、代理池构建等高级主题,将爬取能力提升到新的高度。现在就动手改造你的爬虫,体验多线程带来的效率飞跃吧!

扩展学习资源

【免费下载链接】requests-html Pythonic HTML Parsing for Humans™ 【免费下载链接】requests-html 项目地址: https://gitcode.com/gh_mirrors/re/requests-html

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值