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)。

相关推荐
岁忧5 小时前
GoLang五种字符串拼接方式详解
开发语言·爬虫·golang
程序员小远6 小时前
软件测试之单元测试详解
自动化测试·软件测试·python·测试工具·职场和发展·单元测试·测试用例
心无旁骛~6 小时前
python多进程和多线程问题
开发语言·python
星云数灵6 小时前
使用Anaconda管理Python环境:安装与验证Pandas、NumPy、Matplotlib
开发语言·python·数据分析·pandas·教程·环境配置·anaconda
计算机毕设匠心工作室7 小时前
【python大数据毕设实战】青少年抑郁症风险数据分析可视化系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习
后端·python
计算机毕设小月哥7 小时前
【Hadoop+Spark+python毕设】智能制造生产效能分析与可视化系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
计算机毕设小月哥9 小时前
【Hadoop+Spark+python毕设】中风患者数据可视化分析系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
Keep_Trying_Go9 小时前
基于Zero-Shot的目标计数算法详解(Open-world Text-specified Object Counting)
人工智能·pytorch·python·算法·多模态·目标统计
计算机毕设匠心工作室9 小时前
【python大数据毕设实战】强迫症特征与影响因素数据分析系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习、实战教学
后端·python·mysql