Python多线程数据爬取程序模版

最近一个项目需要爬取很多项目,前期测试需要小批量进程,后期体量上来了,需要增加很多线程,这就要求我们多线程爬虫数据并且要求随时可拓展性,因为Python它有丰富的库支持,所以我的想法首选肯定是python。

下面是一个使用Python编写的多线程数据爬取应用程序示例。这个程序使用threadingqueue模块实现多线程,并通过requests库发送HTTP请求。

python 复制代码
import threading
import queue
import requests
import time
from urllib.parse import urlparse
import csv
import os
​
# 配置参数
MAX_THREADS = 5  # 最大线程数
REQUEST_TIMEOUT = 10  # 请求超时时间(秒)
OUTPUT_FILE = 'crawled_data.csv'  # 输出文件名
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'
}
​
class CrawlerThread(threading.Thread):
    def __init__(self, url_queue, data_queue, lock):
        threading.Thread.__init__(self)
        self.url_queue = url_queue
        self.data_queue = data_queue
        self.lock = lock
        self.session = requests.Session()
​
    def run(self):
        while True:
            try:
                # 从队列获取URL,超时3秒退出
                url = self.url_queue.get(timeout=3)
                self.crawl(url)
                self.url_queue.task_done()
            except queue.Empty:
                break
​
    def crawl(self, url):
        try:
            # 发送HTTP请求
            response = self.session.get(
                url,
                headers=HEADERS,
                timeout=REQUEST_TIMEOUT,
                allow_redirects=True
            )
            response.raise_for_status()  # 检查HTTP错误
​
            # 解析域名
            domain = urlparse(url).netloc
            
            # 将结果放入数据队列
            self.data_queue.put({
                'url': url,
                'domain': domain,
                'status': response.status_code,
                'length': len(response.content),
                'success': True
            })
            
            print(f"[SUCCESS] Crawled: {url} ({response.status_code})")
            
        except Exception as e:
            self.data_queue.put({
                'url': url,
                'error': str(e),
                'success': False
            })
            print(f"[ERROR] Failed {url}: {str(e)}")
​
def data_writer(data_queue, lock, filename):
    """数据写入线程"""
    # 创建CSV文件并写入标题
    with lock:
        with open(filename, 'w', newline='', encoding='utf-8') as f:
            writer = csv.DictWriter(f, fieldnames=['url', 'domain', 'status', 'length', 'error', 'success'])
            writer.writeheader()
    
    while True:
        try:
            data = data_queue.get(timeout=5)
            with lock:
                with open(filename, 'a', newline='', encoding='utf-8') as f:
                    writer = csv.DictWriter(f, fieldnames=['url', 'domain', 'status', 'length', 'error', 'success'])
                    
                    # 仅保留存在的字段
                    row = {key: data.get(key, '') for key in writer.fieldnames}
                    writer.writerow(row)
                    
            data_queue.task_done()
        except queue.Empty:
            # 检查是否所有任务已完成
            if url_queue.empty():
                break
​
def main(urls):
    # 创建队列
    url_queue = queue.Queue()
    data_queue = queue.Queue()
    lock = threading.Lock()
​
    # 填充URL队列
    for url in urls:
        url_queue.put(url)
​
    # 启动爬虫线程
    crawlers = []
    for _ in range(min(MAX_THREADS, len(urls))):
        t = CrawlerThread(url_queue, data_queue, lock)
        t.daemon = True
        t.start()
        crawlers.append(t)
​
    # 启动数据写入线程
    writer_thread = threading.Thread(
        target=data_writer, 
        args=(data_queue, lock, OUTPUT_FILE),
        daemon=True
    )
    writer_thread.start()
​
    # 等待所有URL处理完成
    url_queue.join()
    data_queue.join()
​
    print(f"\n爬取完成! 结果已保存到 {OUTPUT_FILE}")
​
if __name__ == "__main__":
    # 示例URL列表 - 替换为实际需要爬取的URL
    urls_to_crawl = [
        'https://www.example.com',
        'https://www.google.com',
        'https://www.github.com',
        'https://www.python.org',
        'https://www.wikipedia.org',
        'https://www.openai.com',
        'https://www.amazon.com',
        'https://www.microsoft.com'
    ]
    
    print(f"开始爬取 {len(urls_to_crawl)} 个URL...")
    start_time = time.time()
    
    main(urls_to_crawl)
    
    duration = time.time() - start_time
    print(f"总耗时: {duration:.2f} 秒")

主要功能说明:

1、多线程架构

  • 使用线程池模式(CrawlerThread类)
  • 单独的数据写入线程(避免频繁文件I/O阻塞爬虫线程)

2、组件

  • URL队列:管理待爬取URL
  • 数据队列:收集爬取结果
  • 线程锁:确保文件写入安全

3、错误处理

  • 请求超时处理
  • HTTP错误状态码处理
  • 异常捕获和记录

4、数据记录

  • 成功爬取:URL、域名、状态码、内容长度
  • 失败记录:错误信息
  • CSV格式输出(可轻松导入Excel或数据库)

5、配置选项

  • 最大线程数(根据网络条件和目标网站调整)
  • 请求超时时间
  • 自定义请求头(模拟浏览器)
  • 输出文件名

使用说明:

1、安装依赖:

复制代码
pip install requests

2、修改配置:

  • urls_to_crawl列表中添加实际要爬取的URL
  • 调整MAX_THREADS(建议5-10个线程)
  • 修改OUTPUT_FILE改变输出路径

3、运行程序:

复制代码
python crawler.py

注意事项:

1、请求频率控制

  • 可在CrawlerThread.crawl()中添加延时:
bash 复制代码
time.sleep(0.5)  # 添加0.5秒延迟

2、代理支持

  • 添加代理轮换功能:
ini 复制代码
proxies = {'http': 'http://proxy_ip:port', 'https': 'https://proxy_ip:port'}
response = self.session.get(url, proxies=proxies, ...)

这个程序提供了多线程爬虫的基本框架,可以根据具体的实际情况改进行扩展和修改。对于大规模爬取,个人推荐还是使用Scrapy框架或异步IO库(如aiohttp)。

相关推荐
想会飞的蒲公英9 小时前
计算机怎样读取中文文本:编码、清洗与标准化
人工智能·python·自然语言处理
SeaTunnel10 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
深度研习笔记10 小时前
OpenCV工业视觉实战09|项目EXE打包+工控机无环境部署+后台常驻运行,彻底脱离Python环境,完成项目最终交付
python·opencv·webpack
Bright Data10 小时前
DuckDuckGo 搜索爬取器
爬虫·serp·网页数据
CCPC不拿奖不改名10 小时前
大模型推理架构与开源生态知识整理
数据库·windows·python·架构·langchain·开源·github
Marst Code11 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
databook11 小时前
当散点图不够用时:用 t-SNE 可视化多维数据
python·数据分析·数据可视化
我的xiaodoujiao13 小时前
快速学习Python基础知识详细图文教程9--函数进阶
开发语言·python·学习·测试工具
weixin_4080996714 小时前
2026 图片去水印 API 接口完全指南:一键去除图片水印(附 Python/Java/PHP/C# 示例)
java·python·php·图片处理·api调用·图片去水印·石榴智能
去码头整点薯条ing14 小时前
某当网登录滑块【协议+OCR】
爬虫·python·ocr