首页 > 编程语言 >Python多线程案例分析

Python多线程案例分析

时间:2024-05-23 21:01:26浏览次数:20  
标签:thread Python URL queue 案例 url urls import 多线程

接下来,我们将在之前的基础上进一步扩展多线程爬虫案例,增加以下功能:

1. 动态URL发现与添加:爬虫在解析页面时,能够发现并添加新的URL到队列中。
2. 设置请求头:模拟浏览器行为,设置请求头中的`User-Agent`。
3. 使用会话:使用`requests.Session()`对象来保持连接,提高效率。
4. 避免重复爬取:使用集合记录已爬取的URL,避免重复爬取。
5. 更复杂的错误处理:增加对各种网络错误的处理。

### 扩展后的多线程爬虫代码:```python

import requests
from bs4 import BeautifulSoup
import threading
import time
import logging
from queue import Queue
from urllib.parse import urljoin

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 请求会话
session = requests.Session()

# 请求队列
url_queue = Queue()
# 避免重复爬取的集合
visited_urls = set()

def crawl(url):
    if url in visited_urls:
        return
    visited_urls.add(url)
    try:
        response = session.get(url, headers={'User-Agent': 'Mozilla/5.0'}, timeout=5)
        response.raise_for_status()  # 检查请求是否成功
        soup = BeautifulSoup(response.text, 'html.parser')
        # 假设我们爬取的是网页的标题和一些链接
        title = soup.find('title').get_text()
        links = [urljoin(url, a['href']) for a in soup.find_all('a', href=True) if a['href'] not in visited_urls]
        result_queue.put((url, title))
        # 将新发现的链接添加到队列中
        for link in links:
            url_queue.put(link)
        logging.info(f"成功爬取: {url}")
    except requests.RequestException as e:
        logging.error(f"请求错误: {url} - {e}")
    except Exception as e:
        logging.error(f"解析错误: {url} - {e}")

def worker():
    while not url_queue.empty():
        url = url_queue.get()
        crawl(url)
        # 模拟网络延迟
        time.sleep(0.5)

def manage_threads(url_list, thread_count=5):
    # 将初始URL加入队列
    for url in url_list:
        if url not in visited_urls:
            url_queue.put(url)

    # 创建并启动线程
    threads = []
    for _ in range(thread_count):
        thread = threading.Thread(target=worker)
        threads.append(thread)
        thread.start()

    # 等待所有线程完成
    for thread in threads:
        thread.join()

    # 打印结果
    while not result_queue.empty():
        url, title = result_queue.get()
        print(f"URL: {url}, Title: {title}")

# 爬取的URL列表
urls = [
    'http://example.com',
    # 添加更多URL...
]

if __name__ == "__main__":
    manage_threads(urls, thread_count=10)


```

### 案例详解:

- 动态URL发现与添加:在`crawl`函数中,解析页面后发现的链接会动态添加到`url_queue`中,以便进行爬取。
- 设置请求头:在`session.get`中添加了`headers`参数,模拟浏览器的`User-Agent`。
- 使用会话:使用`requests.Session()`对象发起请求,可以保持连接,提高效率。
- 避免重复爬取:通过`visited_urls`集合记录已爬取的URL,避免重复爬取同一页面。
- 更复杂的错误处理:在`crawl`函数中,增加了对网络错误的处理。

### 注意事项:

- 线程安全:确保对共享资源(如`url_queue`和`visited_urls`)的操作是线程安全的。
- 会话管理:使用`session`对象时,要注意其线程安全性。在某些情况下,可能需要为每个线程创建独立的会话。
- 动态URL管理:动态添加URL时,要注意避免无限循环,特别是当爬虫遇到重定向或循环链接时。
- 性能调优:根据实际情况调整线程数量和请求间隔,以达到最佳的爬取效率。

这个案例提供了一个更完整的多线程爬虫框架,包括动态URL发现、会话管理等高级功能。在实际应用中,你可能需要根据目标网站的特点和反爬措施进行相应的调整和优化。

在前面的基础上,我们将继续扩展我们的多线程爬虫案例,增加以下高级功能:

1. robots.txt 遵守:检查网站的`robots.txt`文件,确保爬虫遵守网站的爬取规则。
2. 重试机制:对失败的请求实施重试策略。
3. IP代理:使用代理IP来绕过网站的IP封锁。
4. 数据存储:将爬取的数据存储到文件或数据库中。
5. 更细粒度的速率限制:使用更高级的速率限制策略,如令牌桶算法。

### 扩展后的多线程爬虫代码:```python

import requests
from bs4 import BeautifulSoup
import threading
import time
import logging
from queue import Queue
from urllib.parse import urljoin, urlparse
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 请求会话
session = requests.Session()

# 重试策略
retry_strategy = Retry(
    total=3,  # 总共重试3次
    status_forcelist=[429, 500, 502, 503, 504],  # 重试状态码
    method_whitelist=["HEAD", "GET", "OPTIONS"],  # 允许重试的方法
    backoff_factor=1  # 退避因子
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)

# 请求队列
url_queue = Queue()
# 避免重复爬取的集合
visited_urls = set()
# 存储爬取结果的列表
crawl_results = []

def crawl(url):
    if url in visited_urls:
        return
    visited_urls.add(url)
    try:
        response = session.get(url, headers={'User-Agent': 'Mozilla/5.0'}, timeout=5)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, 'html.parser')
        title = soup.find('title').get_text()
        links = [urljoin(url, a['href']) for a in soup.find_all('a', href=True)]
        crawl_results.append((url, title))
        for link in links:
            if link not in visited_urls:
                url_queue.put(link)
        logging.info(f"成功爬取: {url}")
    except requests.RequestException as e:
        logging.error(f"请求错误: {url} - {e}")
    except Exception as e:
        logging.error(f"解析错误: {url} - {e}")

def worker():
    while not url_queue.empty():
        url = url_queue.get()
        crawl(url)
        # 细粒度速率限制
        time.sleep(0.5)

def manage_threads(url_list, thread_count=5):
    for url in url_list:
        if url not in visited_urls:
            url_queue.put(url)

    threads = []
    for _ in range(thread_count):
        thread = threading.Thread(target=worker)
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()

    # 打印结果
    for result in crawl_results:
        print(result)

# 爬取的URL列表
urls = [
    'http://example.com',
    # 添加更多URL...
]

if __name__ == "__main__":
    manage_threads(urls, thread_count=10)

    # 将结果存储到文件
    with open('crawl_results.txt', 'w', encoding='utf-8') as file:
        for url, title in crawl_results:
            file.write(f"URL: {url}, Title: {title}\n")


```

### 案例详解:

- robots.txt 遵守:可以通过`robotparser`模块来解析网站的`robots.txt`文件,并检查是否允许爬取特定的URL。
- 重试机制:使用`requests`的`Retry`和`HTTPAdapter`来实现请求的重试策略。
- IP代理:可以在`session.get`中设置代理,例如使用`proxies`参数。
- 数据存储:将爬取的结果存储到文件中,也可以根据需求存储到数据库或其他存储系统中。
- 细粒度速率限制:在`worker`函数中,通过`time.sleep(0.5)`实现简单的速率限制。

### 注意事项:

- robots.txt 遵守:在实际应用中,应当遵守`robots.txt`协议,尊重网站的爬取规则。
- 重试策略:合理配置重试策略,避免对服务器造成过大压力。
- 代理使用:使用代理时,应确保代理的稳定性和可靠性。
- 数据存储:根据实际需求选择合适的数据存储方案。
- 速率限制:合理设置请求间隔,避免触发网站的反爬机制。

这个案例提供了一个更为完善的多线程爬虫框架,包括遵守`robots.txt`、重试策略、使用代理、数据存储和细粒度速率限制等功能。在实际应用中,你可能需要根据目标网站的特点和反爬措施进行相应的调整和优化。

标签:thread,Python,URL,queue,案例,url,urls,import,多线程
From: https://blog.csdn.net/hummhumm/article/details/139151063

相关文章

  • Python 将PowerPoint (PPT/PPTX) 转为HTML
    1.Python 将PowerPoint文档转为HTML格式要实现该转换,仅需加一个.ppt或.pptx文档,然后使用 Presentation.SaveToFile() 方法将其另存为HTML格式。fromspire.presentation.commonimport*fromspire.presentationimport*#加载PPT文档ppt=Presentation()ppt.L......
  • 利用Python训练手势模型代码
    importcv2ascvimportosimportnumpyasnpfromsklearn.decompositionimportPCAfromsklearn.model_selectionimporttrain_test_splitfromsklearn.svmimportSVCfromsklearn.treeimportDecisionTreeClassifierfromsklearn.neighborsimportKNeighborsClassifie......
  • python 基础习题3--数据类型和运算符
    1.  100/4+2*3 运行结果是 ()                    A、10B、81C、31D、50    E、31.02. Python 中的== 代表的是 (  )A、把左边的值赋值给右边;B、把右边的值赋值给左边 ;C、比较左右......
  • python计算雨水含量(W)
     数据: #!usr/bin/envpython#-*-coding:utf-8-*-"""@author:Suyue@file:raincontent.py@time:2024/05/23@desc:"""importnumpyasnpimportpandasaspdimportxlwtimportmathdf1=pd.read_excel('20240510五原数浓......
  • python DataFrame之MultiIndex 的使用
    importpandasaspdimportpprintasp#嵌套列表arrays=[['a','a','b','b'],[1,2,1,2]]#创建MultiIndexindex=pd.MultiIndex.from_arrays(arrays,names=('letter','number'))#使用MultiInd......
  • [Python] pipe模块
    一.概述我们都知道在Linux下执行命令ls|sort-r会将排序后的结果进行输出,它是先获取目录数据,管道符|将ls的输出作为后一个命令的输入,最终得到反向排序的结果。Python和其他大多数语言一样,处理数据的时候通常是将数据作为参数传入。但是有没有像Linux管道符那样优雅的输出呢?有......
  • 买卖股票相关算法-动态规划-python
    要求1:给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不......
  • Pairwise实现(Python篇)
    开篇:测试过程中,对于多参数参数多值的情况进行测试用例组织,之前一直使用【正交分析法】进行用例组织,说白了就是把每个参数的所有值分别和其他参数的值做一个全量组合,用Python脚本实现,就是itertools模块中product方法(又称笛卡尔积法)。组合生成器,例:importitertoolsa=(......
  • python多进程感悟
    对于大量的测试数据,使用多进程时(例如8个进程),最好使用queue来消费数据,不要将测试数据分为8个list,分别送入不同的进程中,因为这样可以避免极端情况出现。例如,每个测试数据处理起来耗时不一样,你刚好把耗时比较长的数据分了同一个list,就会导致其他的进程也会一直等待该进程的完成。......
  • 振弦采集仪在岩土工程边坡稳定性监测中的实践与案例分析
    振弦采集仪在岩土工程边坡稳定性监测中的实践与案例分析河北稳控科技振弦采集仪是一种用于岩土工程边坡稳定性监测的仪器设备,用于采集边坡体动力特性参数,能够对边坡的稳定性进行实时监测和预警。在实践中,振弦采集仪已经被广泛应用于岩土工程边坡稳定性监测中,并取得了良好的效果。......