Playwright进行异步爬取案例

1.代码功能概述

该代码使用 Playwright 异步库编写,用于抓取一个目标网站的数据。主要任务包括:

  1. 加载网页:访问指定页面并等待加载完成。
  2. 解析网页内容:提取数据如标题、封面图片、分类、评分、简介等。
  3. 存储数据:将抓取到的数据以特定格式保存到本地文件中。

2.代码结构解析

1. 导入模块

import asyncio
import logging
from os.path import exists
from playwright.async_api import async_playwright
from urllib.parse import urljoin
  • asyncio:用于异步操作。
  • logging:用于记录程序的运行日志。
  • os.path.exists:检查指定路径是否存在。
  • async_playwright:Playwright 异步版本,用于浏览器自动化。
  • urljoin:用于拼接相对路径和基准路径,生成完整的 URL。

2. 全局变量与初始化

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
BASE_URL = 'https://ssr1.scrape.center'
TOTAL_PAGE = 2
RESULT_DIR = 'data'
exists(RESULT_DIR) or makedirs(RESULT_DIR)
  • 设置日志记录格式和级别。
  • 定义爬取的目标网站的基本 URL (BASE_URL) 和总页数 (TOTAL_PAGE)。
  • RESULT_DIR:存储数据的目录。
  • 如果结果存储目录不存在,则创建该目录。

3. 页面加载功能

async def scrape_page(page, url):
    logging.info('scraping %s ...', url)
    try:
        await page.goto(url)  # 跳转到目标 URL
        await page.wait_for_load_state('networkidle')  # 等待页面完全加载
    except Exception as e:
        logging.error(f"Error scraping {url}: {str(e)}", exc_info=True)
        return False
    return True
  • 功能:访问指定的网页 URL,等待其加载完成。
  • 异常处理:如果加载失败,记录错误并返回 False

4. 索引页和详情页抓取功能

async def scrape_index(page, page_index):
    index_url = f'{BASE_URL}/page/{page_index}'
    return await scrape_page(page, index_url)

async def scrape_detail(page, url):
    return await scrape_page(page, url)
  • scrape_index:访问分页列表页。
  • scrape_detail:访问详情页。

5. 索引页内容解析

async def parse_index(page):
    elements = await page.query_selector_all('a.name')  # 找到所有目标链接
    for element in elements:
        part_of_url = await element.get_attribute('href')  # 获取链接地址
        if part_of_url:
            detail_url = urljoin(BASE_URL, part_of_url)  # 拼接完整 URL
            logging.info('get url: %s', detail_url)
            yield detail_url
  • 查找页面中所有指定的 <a> 标签,并提取其 href 属性。
  • 通过 urljoin 拼接为完整的详情页 URL。

6. 详情页内容解析

async def parse_detail(page):
    name_tag = await page.query_selector('h2.m-b-sm')
    name = await name_tag.text_content() if name_tag else None

    cover_tag = await page.query_selector('img.cover')
    cover = await cover_tag.get_attribute('src') if cover_tag else None

    category_tags = await page.query_selector_all('div.categories > button > span')
    categories = [await category.text_content() for category in category_tags] if category_tags else []

    score_tag = await page.query_selector('p.score')
    score = await score_tag.text_content().strip() if score_tag else None

    drama_tag = await page.query_selector('div.drama > p')
    drama = await drama_tag.text_content().strip() if drama_tag else None

    return {
        'name': name,
        'cover': cover,
        'categories': categories,
        'drama': drama,
        'score': score
    }
  • 使用 CSS 选择器提取以下内容:
    • 标题h2.m-b-sm
    • 封面图片链接img.cover
    • 分类div.categories > button > span
    • 评分p.score
    • 简介div.drama > p
  • 每个字段都有空值检查,避免因元素缺失导致错误。

7. 数据存储

async def save_data(data):
    data_path = '{0}/movies_selector_async.txt'.format(RESULT_DIR)
    with open(data_path, 'w', encoding='utf-8') as file:
        name = data.get('name', None)
        cover = data.get('cover', None)
        categories = data.get('categories', None)
        drama = data.get('drama', None)
        score = data.get('score', None)

        file.write('name:'+name+'\n')
        file.write('cover:'+cover+'\n')
        file.write('categories:'+str(categories)+'\n')
        file.write('drama:'+drama+'\n')
        file.write('score:'+score+'\n')
        file.write('='*50 + '\n')
  • 数据格式化后写入文件,采用 key:value 格式,并用分隔线分隔。

8. 主函数

async def main():
    logging.info("开始采集")
    playwright = await async_playwright().start()
    browser = await playwright.chromium.launch(headless=True)
    context = await browser.new_context()
    page_1 = await context.new_page()
    page_num = 3
    flag = 0

    for i in range(1, page_num):
        url = "https://spa6.scrape.center/page/"+str(i)
        await page_1.goto(url)
        await page_1.wait_for_load_state('networkidle')
        elements = await page_1.query_selector_all('div.el-card.item.m-t.is-hover-shadow')

        page_2 = await context.new_page()
        for element in elements:
            logging.info("子页面采集开始")
            tag_a = await element.query_selector('a')
            detail_url = 'https://spa6.scrape.center' + await tag_a.get_attribute('href')
            await scrape_detail(page_2, detail_url)
            data = await parse_detail(page_2)
            logging.info('get data: %s', data)
            await save_data(data)
            logging.info("子页面采集结束")
            flag = flag+1

    logging.info("全部数据采集结束,共:{}条".format(flag))
    await browser.close()
  • 打开浏览器并创建上下文与页面。
  • 遍历分页,提取每页的所有详情链接并依次访问。
  • 调用解析函数提取数据并保存。
    在这里插入图片描述
<think>好的,用户想比较Python和Java在爬虫开发中的特点和适用场景。首先,我需要回忆两种语言在爬虫方面的常见库和特性。 Python方面,常用的库有Requests、BeautifulSoup、Scrapy和Selenium。这些库各有优势,比如Requests处理HTTP请求,BeautifulSoup解析HTML,Scrapy适合大规模爬虫,Selenium处理动态页面。Python语法简洁,适合快速开发,但可能在性能上不如Java。 Java方面,常用的库有Jsoup、HtmlUnit、WebMagic和Apache Nutch。Jsoup用于解析HTML,HtmlUnit处理JavaScript,WebMagic框架适合结构化爬虫,Nutch适用于分布式大规模爬取。Java性能较好,多线程和分布式处理更强,适合企业级应用,但代码量可能更大,开发周期长。 接下来需要考虑两者的对比点:语法简洁性、库生态、性能、适用场景。Python适合快速开发和小项目,Java适合高性能和大规模需求。需要引用用户提供的参考,比如提到Selenium的部分,引用[^3],说明其在动态页面处理中的应用。另外,用户提供的引用[^1]中有关于Python库如boto3、google-api等,可能可以提及Python在集成其他云服务时的便利性,但不确定是否相关,可能需要谨慎引用。 用户可能还关心实际案例,比如Python适合数据挖掘、科研,Java适合电商价格监控等。需要确保信息准确,比如Scrapy的异步处理,Java的JVM优化。 最后生成相关问题,要围绕爬虫开发,比如库的选择、性能优化、动态页面处理、扩展性考虑等。需要检查是否符合用户的要求,问题要有实际意义,帮助深入理解主题。</think>### Python vs Java 在爬虫开发中的对比 #### 一、核心特性与语法差异 1. **Python** - **语法简洁性**:动态类型和简洁语法(如列表推导、装饰器)显著减少代码量,适合快速验证爬虫逻辑。例如,用`requests`库抓取网页仅需3行代码: ```python import requests response = requests.get("https://example.com") print(response.text) ``` - **交互式开发**:支持Jupyter Notebook实时调试,适合数据清洗和解析测试。 2. **Java** - **静态类型与严谨性**:编译期类型检查减少运行时错误,适合长期维护的大型项目。例如,使用`Jsoup`解析HTML需明确处理异常: ```java try { Document doc = Jsoup.connect("https://example.com").get(); System.out.println(doc.title()); } catch (IOException e) { e.printStackTrace(); } ``` - **多线程支持**:原生`java.util.concurrent`包提供线程池、锁机制,适合高并发爬取(如同时监控数千个页面)。 --- #### 二、库生态对比 | 功能 | Python 库 | Java 库 | |-----------------|---------------------------------------|--------------------------------------| | **HTTP请求** | `requests`(同步)、`aiohttp`(异步) | `HttpClient`、`OkHttp` | | **HTML解析** | `BeautifulSoup`、`lxml` | `Jsoup`、`HtmlUnit`(支持JS渲染) | | **爬虫框架** | `Scrapy`(异步引擎+中间件扩展) | `WebMagic`(模块化设计)、`Apache Nutch`(分布式) | | **动态渲染** | `Selenium`、`Playwright` | `Selenium`、`HtmlUnit` | | **数据存储** | `SQLAlchemy`(ORM)、`pandas`(CSV) | `Hibernate`、`Spring Data` | **关键点**: - Python的`Scrapy`内置中间件支持自动限速、UA轮换,而Java的`WebMagic`需手动扩展。 - Java的`HtmlUnit`可直接解析JavaScript,无需启动浏览器,资源消耗低于Python的`Selenium`。 --- #### 三、性能与扩展性 1. **执行效率** - **CPU密集型任务**:Java凭借JIT编译优化,处理复杂解析(如XPath提取10万条数据)速度比Python快2-3倍。 - **I/O密集型任务**:Python通过`asyncio`协程实现高并发(如同时管理500个网络连接),代码复杂度低于Java的NIO。 2. **分布式扩展** - Java的`Apache Nutch`支持Hadoop集成,适合PB级数据爬取(如全网搜索引擎)。 - Python可通过`Scrapy-Redis`实现分布式,但节点通信效率低于Java生态。 --- #### 四、典型应用场景 1. **Python 适用场景** - **快速原型开发**:例如初创公司需在2天内抓取竞品价格数据。 - **学术研究**:结合`pandas`和`matplotlib`直接分析爬取结果。 - **轻量级监控**:例如每日定时抓取100个新闻网站标题。 2. **Java 适用场景** - **企业级爬虫系统**:例如银行需合规审计,抓取百万级金融交易记录并持久化到Oracle。 - **高防反爬场景**:利用`代理池+分布式调度`突破反爬策略,如电商平台价格监控。 - **与JavaEE整合**:例如将爬虫作为Spring Boot微服务的一部分。 --- #### 五、选择建议 - **选Python**:项目周期短(<3个月)、需与数据科学工具链(如Jupyter)整合、团队Python熟练度高。 - **选Java**:系统需7*24小时稳定运行、处理数据量超过1TB/天、已有Java微服务架构。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

油泼辣子多加

感谢大佬!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值