抓取网页数据的高级技巧:结合 Popen() 与 stdout 处理异步任务

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 本文介绍了如何利用 `Popen()` 和 `stdout` 处理异步任务,结合代理IP和多线程技术提高爬虫效率。通过实例展示了如何在项目中集成这些技术,包括设置代理IP、多线程任务分发及新闻标题提取等关键步骤。文章还探讨了性能提升的方法和扩展方案,如使用 `asyncio` 和数据库集成,适合大规模数据抓取场景。

爬虫代理.jpg

1. 引言

在网页数据抓取过程中,处理大量请求和数据通常面临时间和资源的挑战。本文将介绍如何使用 Popen()stdout 处理异步任务,结合代理IP技术和多线程提高爬虫效率。我们将参考爬虫代理提供的服务,详细讲解如何在实际项目中集成这些技术。

2. 异步任务的必要性

传统的单线程爬虫由于需要依次等待每个请求返回,往往在面对大量网页数据时效率低下。而异步任务可以让程序在处理某些任务时,同时执行其他操作,提高数据抓取速度。通过 Popen() 调用子进程并结合 stdout 读取子进程的输出,可以实现异步爬虫的优化。

3. Popen()stdout 介绍

subprocess.Popen() 是 Python 中用于执行外部命令的模块。它能够启动子进程,并通过 stdout 获取子进程的输出流,使得主进程可以在等待子进程完成时继续处理其他任务。

Popen() 方法支持异步操作,配合多线程或异步库,可以进一步提升爬虫的并发性能。

4. 代理IP技术与多线程爬虫设计

爬虫使用代理IP可以避免被目标网站封锁,尤其是在请求量较大的情况下。爬虫代理提供了安全、快速的代理服务,本文将在爬虫代码中集成它的域名、端口、用户名和密码。同时,多线程的引入能有效提高数据采集的并发能力。

5. 实现代码示例

import threading
import subprocess
import requests
from queue import Queue
import re

# 代理IP设置 (参考亿牛云爬虫代理 www.16yun.cn)
proxy_host = "proxy.16yun.cn"  # 代理域名
proxy_port = "8080"  # 代理端口
proxy_user = "username"  # 用户名
proxy_pass = "password"  # 密码

# 设置代理IP
proxies = {
   
   
    "http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
    "https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
}

# 任务队列,用于存储要抓取的网址
url_queue = Queue()

# 示例新闻网站URL列表
url_list = [
    "https://news.sina.com.cn/",  # 新浪新闻
    "https://www.163.com/news/",  # 网易新闻
    "https://news.qq.com/",  # 腾讯新闻
    "https://www.chinanews.com/",  # 中国新闻网
    # 可以继续添加更多新闻网站
]

# 定义用于存储新闻标题的全局列表
news_titles = []

# 正则表达式匹配标题,针对常见HTML结构
title_regex = re.compile(r"<title>(.*?)</title>", re.IGNORECASE)

# 定义爬虫任务,使用Popen调用curl,并从stdout获取输出
def crawl(url):
    try:
        print(f"正在抓取: {url}")

        # 使用Popen异步执行curl命令,并通过代理访问
        process = subprocess.Popen(
            ["curl", "-x", f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}", url],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )

        # 读取标准输出和错误输出
        stdout, stderr = process.communicate()

        if process.returncode == 0:
            # 解码抓取到的网页内容为字符串
            webpage_content = stdout.decode('utf-8')

            # 使用正则表达式提取网页标题
            title_match = title_regex.search(webpage_content)
            if title_match:
                title = title_match.group(1)
                news_titles.append({
   
   "url": url, "title": title})
                print(f"成功提取新闻标题: {title}")
            else:
                print(f"未能提取到标题: {url}")
        else:
            print(f"抓取失败: {url}\n错误信息: {stderr.decode('utf-8')}")

    except Exception as e:
        print(f"爬取过程中出现异常: {str(e)}")

# 多线程任务分发
def thread_task():
    while not url_queue.empty():
        url = url_queue.get()
        crawl(url)
        url_queue.task_done()

# 将URL列表放入任务队列
for url in url_list:
    url_queue.put(url)

# 创建并启动多线程,每个线程执行thread_task函数
thread_count = 5  # 线程数量
threads = []

for _ in range(thread_count):
    t = threading.Thread(target=thread_task)
    t.start()
    threads.append(t)

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

# 输出抓取到的新闻标题
print("\n抓取到的所有新闻标题:")
for news in news_titles:
    print(f"网站: {news['url']}, 标题: {news['title']}")

print("所有抓取任务完成。")

6. 代码解析

  1. 新闻网站URL列表
    我们调整了目标网站为新闻网站,如新浪新闻、网易新闻、腾讯新闻和中国新闻网。这些网站有大量新闻,可以作为目标网页进行抓取。
  2. 新闻标题提取
    使用正则表达式 title_regex 匹配新闻网站的 <title> 标签内容,从抓取到的网页中提取出每条新闻的标题。此方法适用于绝大部分网站的标题提取。
  3. 代理IP设置
    代理IP仍然采用爬虫代理服务,确保通过代理访问目标网站,提高采集效率。
  4. 多线程任务分发
    使用 threading 模块实现多线程爬虫,每个线程从任务队列中取出一个URL进行抓取,并将抓取到的新闻标题归类存储,提升抓取效率。
  5. 新闻标题分类存储
    所有抓取到的新闻标题被按其来源网站进行存储,并最终通过一个列表输出显示。

7. 性能提升与扩展

  • 多线程与代理结合:通过多线程与代理IP结合使用,本爬虫可以同时抓取多个新闻网站的数据,提高抓取效率,并规避IP封锁。
  • 数据存储扩展:可以进一步将提取到的新闻标题存储到数据库中(如 MySQL 或 MongoDB),并结合分类和检索功能,实现大规模新闻数据的管理和分析。

8. 性能提升的分析

通过结合 Popen()stdout 处理异步任务,可以避免传统爬虫因等待网络响应而造成的阻塞,显著提高爬虫的性能。使用多线程进一步增强了并发处理能力。在实际使用中,我们可以根据系统资源调整线程数量,以找到性能和资源利用率的最佳平衡点。

9. 结论

在网页数据抓取中,结合 Popen()stdout 处理异步任务,配合代理IP和多线程技术,可以有效提高爬虫的效率和稳定性。本文通过实例演示了如何将这些技术集成到一个爬虫项目中,读者能在实际项目中灵活应用,打造更高效的网页数据抓取方案。

10. 更新与扩展

该技术方案可以根据需求进一步扩展,例如:

  • 使用 asyncioaiohttp 进一步提升异步性能。
  • 集成数据库,将抓取的数据实时存储。
  • 结合分布式系统进行大规模数据抓取。

11. 结论

这篇示例文章展示了如何结合 Popen()stdout 和代理IP技术,构建一个高效的多线程爬虫,用于抓取新闻网站的新闻标题,并按来源分类存储。这种技术方案适用于大规模新闻数据采集,具有高效性和稳定性。

相关文章
|
28天前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
27 6
|
5月前
|
容器
这个错误是因为在读取文件时,管道已经结束
【1月更文挑战第14天】【1月更文挑战第67篇】这个错误是因为在读取文件时,管道已经结束
98 4
|
Python
Python中标准输入(stdin)、标准输出(stdout)、标准错误(stdout)的用法
Python中标准输入(stdin)、标准输出(stdout)、标准错误(stdout)的用法
142 0
|
移动开发 缓存 安全
python 标准类库-并行执行之subprocess-子进程管理
python 标准类库-并行执行之subprocess-子进程管理
227 0
|
Python
Python编程:subprocess执行命令行命令
Python编程:subprocess执行命令行命令
250 0
Python编程:subprocess执行命令行命令
rxjs的pipe和map配合使用的单步调试
rxjs的pipe和map配合使用的单步调试
207 0
rxjs的pipe和map配合使用的单步调试
rxjs pipe和filter组合的一个实际例子的单步调试
rxjs pipe和filter组合的一个实际例子的单步调试
258 0
rxjs pipe和filter组合的一个实际例子的单步调试
|
数据处理 Python
帅到爆炸!使用管道 Pipe 编写 Python 代码竟如此简洁
众所周知,Pytnon 非常擅长处理数据,尤其是后期数据的清洗工作。今天派森酱就给大家介绍一款处理数据的神器 Pipe。
847 0
|
Java Android开发 Windows
写个批处理脚本来帮忙干活--遍历文件夹&字符串处理
原文:写个批处理脚本来帮忙干活--遍历文件夹&字符串处理 这次打算写几篇关于脚本方面的博客,主要是记录一下 Gradle 脚本和批处理脚本的一些写法,方便后续查阅。 前言 平常开发过程中,一些较为重复的手工性工作,如果能让脚本来帮忙处理,自然是最好的,刚好之前有些工作有点过于重复且都是手工性去完成,所以就想着能否写个脚本来处理。
1081 0