目录

使用 Playwright 获取大众点评店铺评论

目录

简单记录使用playwright获取大众点评店铺评论的方法。

大概一年前使用playwright替换了selenium写爬虫,使用playwright自带脚本生成简单的代码并且保存登陆状态更加方便。最近因为某个原因要写一下大众点评的爬虫,简单记录一下整个过程。

在终端中执行下面的命令,开始代码生成。在弹出的浏览器窗口中访问网站,并登录。相关的一系列行为都会被记录下来,并生成对应的代码。当关闭代码生成界面之后,登陆状态也会被保存在指定的 session.json 文件下。

python -m playwright codegen --save-storage=session.json

下面是获取评论区脚本的具体实现方式。

  • 首先加载已经保存过的 session.json 文件,之后创建一个page并且访问到指定的地址,并执行一行js命令让页面滑动到最底部。(页面滑动功能本来我不会写,但使用 copilot 给出注释之后它自动帮我补全了)
  • 等待所有的评论区被加载完成,这里用到了 wait_for_selector 使脚本强制等待
  • 定位 comments 列表,把列表中的所有项遍历,保存我们想要的信息
  • 因为这个网站的下一页按钮是不会发生变化的,所以在执行完访问功能之后会直接点击按钮,并等待几秒钟避免频率过高被反爬

这段代码执行了大概半个小时爬完了大概是三百多页的数据,每页15个评论。过程中只出现一次要求输入滑动验证的情况,由于设置了等待加载,手动输入验证之后就可以继续工作,之后就再也没有出现过相关的提示,可能是这个访问频率设置还比较合理。

# 使用 playwright 加载本地 session.json
# 访问 https://www.dianping.com/shop/l9dVct5Ly4pFdw9e/review_all
# 记录所有评论ID和链接
# 自动翻页

from playwright.sync_api import sync_playwright

fname = 'comments.csv'

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    
    # 加载session
    context = browser.new_context(storage_state='session.json')
    page = context.new_page()
    
    # 访问评论页面
    page.goto('https://www.dianping.com/shop/l9dVct5Ly4pFdw9e/review_all')

    while True:
        # 滑动到底部
        page.evaluate('''() => {
            window.scrollTo(0, document.body.scrollHeight);
        }''')

        # 等待评论加载完成
        page.wait_for_selector(
            '#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items')

        # 获取评论ID和链接保存到csv文件
        comments = page.query_selector_all(
            '#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items > ul > li')
        # 输出评论个数
        print(len(comments))
        for comment in comments:
            # 获取用户名和链接 .div > div.dper-info > a
            user = comment.query_selector('.dper-info > a')

            # 用户名被 a 包裹
            user_name = user.inner_text()
            user_url = user.get_attribute('href')
            print(user_name, user_url)

            # 获取评论内容 #review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items > ul > li:nth-child(2) > div > div.review-words.Hide
            comment_content = comment.query_selector('.review-words').inner_text()
            # 去除评论中的换行符和多余空格
            comment_content = comment_content.replace('\n', '').replace(' ', '')

            # 评论时间 #review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items > ul > li:nth-child(2) > div > div.misc-info.clearfix > span.time
            comment_time = comment.query_selector('.misc-info.clearfix > span.time').inner_text()

            # 写入csv文件
            with open(fname, 'a', encoding='utf-8') as f:
                f.write(f'{user_name},{user_url},{comment_content},{comment_time}\n')

        # 翻页 #review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.bottom-area.clearfix > div > a.NextPage
        next_page = page.query_selector('#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.bottom-area.clearfix > div > a.NextPage')
        if next_page:
            # 点击下一页
            next_page.click()
        else:
            break

        # 等待5秒
        page.wait_for_timeout(5000)

一个现实的问题是,大众点评的评论区用到了 CSS 反爬虫,但由于我只需要 ID 和大概的评论内容,就没有深追,网上有很多博客讨论了如何破解 CSS 反爬。