Python爬虫实战:如何应对某众点评网的花式反爬策略?

  某众点评网的反爬措施是真的🐮,但误伤率也比较高。如果没有加农炮(加强型爬虫代理 IP ),获取到的数据量会少之又少。

  除此之外,该网站设置了多种反爬措施,多种数据逻辑障碍等来 ban 爬虫,是我目前为止碰到的最难缠的网站。

  但是如果你真的造完该站点的爬虫程序,你会发现维护很累,基本上一天一个样(可能有点夸张)。但是作为训练目标,真的很有收获。

https://github.com/Northxw/Dianping 项目已提交 github,欢迎提交 issue。


Python爬虫实战:如何应对某众点评网的花式反爬策略?

53 回复

我记得在一篇文章里面读到过一个说法,反爬不是为了阻止爬虫,而是为了增加爬虫难度,所以要一天一个样,比的就是勤勉。

有谁能够讲一讲爬虫和反爬的道理?论理不论事。请不吝赐教!


import requests
import time
import random
from fake_useragent import UserAgent
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class DianpingSpider:
    def __init__(self):
        self.ua = UserAgent()
        self.session = requests.Session()
        self.setup_headers()
        
    def setup_headers(self):
        """设置基础请求头"""
        self.session.headers.update({
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.9',
            'Accept-Encoding': 'gzip, deflate, br',
            'Connection': 'keep-alive',
            'Upgrade-Insecure-Requests': '1',
            'Sec-Fetch-Dest': 'document',
            'Sec-Fetch-Mode': 'navigate',
            'Sec-Fetch-Site': 'none',
            'Cache-Control': 'max-age=0'
        })
    
    def get_dynamic_headers(self):
        """生成动态请求头"""
        return {
            'User-Agent': self.ua.random,
            'Referer': 'https://www.dianping.com/',
            'X-Requested-With': 'XMLHttpRequest' if random.random() > 0.5 else None
        }
    
    def rotate_proxy(self):
        """代理IP轮换(示例结构)"""
        # 实际使用时需要配置代理池
        proxies = {
            'http': 'http://your_proxy:port',
            'https': 'https://your_proxy:port'
        }
        return proxies if random.random() > 0.7 else None
    
    def human_like_delay(self):
        """模拟人类操作间隔"""
        time.sleep(random.uniform(1.5, 3.5))
    
    def bypass_webdriver_detection(self):
        """使用Selenium绕过WebDriver检测"""
        options = webdriver.ChromeOptions()
        options.add_argument('--disable-blink-features=AutomationControlled')
        options.add_experimental_option("excludeSwitches", ["enable-automation"])
        options.add_experimental_option('useAutomationExtension', False)
        
        driver = webdriver.Chrome(options=options)
        driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
            'source': '''
                Object.defineProperty(navigator, 'webdriver', {get: () => undefined})
                window.chrome = {runtime: {}}
            '''
        })
        return driver
    
    def handle_ajax_data(self, shop_id):
        """处理AJAX加载的数据"""
        url = f'https://www.dianping.com/ajax/json/shopDynamic/allReview'
        params = {
            'shopId': shop_id,
            'cityId': 1,
            'page': 1,
            '_': int(time.time() * 1000)
        }
        
        headers = self.get_dynamic_headers()
        response = self.session.get(url, params=params, headers=headers)
        
        if response.status_code == 200:
            return response.json()
        return None
    
    def parse_with_selenium(self, url):
        """使用Selenium解析页面"""
        driver = self.bypass_webdriver_detection()
        try:
            driver.get(url)
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CLASS_NAME, "review-list"))
            )
            
            # 模拟滚动加载
            for _ in range(3):
                driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
                time.sleep(random.uniform(2, 4))
            
            # 提取数据
            reviews = driver.find_elements(By.CLASS_NAME, "review-words")
            return [review.text for review in reviews[:5]]
        finally:
            driver.quit()
    
    def main_crawl(self, target_url):
        """主爬取函数"""
        print("开始爬取...")
        
        # 方法1: 直接请求(适合简单页面)
        headers = self.get_dynamic_headers()
        response = self.session.get(target_url, headers=headers)
        
        if response.status_code == 403:
            print("触发反爬,切换到Selenium方案")
            # 方法2: 使用Selenium
            data = self.parse_with_selenium(target_url)
            return data
        elif response.status_code == 200:
            # 解析响应内容
            # 这里添加具体的解析逻辑
            return "直接请求成功"
        
        self.human_like_delay()
        return None

# 使用示例
if __name__ == "__main__":
    spider = DianpingSpider()
    result = spider.main_crawl("https://www.dianping.com/shop/12345678")
    print(f"爬取结果: {result}")

核心思路就是多手段组合:随机请求头+动态间隔+Selenium反检测+代理备用。

#1 “比的就是勤勉” 🐂

只要能被用户看到,理论上就可以被爬,但是大规模的爬已经有很多方法控制,现在就是小规模爬取上面打游击战

楼主有研究过登录吗?登录接口需要带 cookie 才能成功的那种,而 cookie 的获取方式需要在页面上触发 click 事件从而发 http request。

所以 cookie 池出现了

点评是真的变态,我现在网页版基本就处于没法用的状态,打开一家餐厅就验证,验证以后还不会自动跳转

点评我网页版也经常用不了,后来才知道是反爬……

爬客户端协议🌚

高德的反爬从来不会限制你 IP 对服务器的访问,我需要抓取的数据里面有一个 list,顺序很重要。高德的反爬是将这个 list 的排序打乱,而你又要花计算成本去计算这个 list 是否正确。所以根本不是反爬虫,而增加了爬虫成本。

谢谢指点!祝好!

您和那篇文章作者有同样的看法,看来高手在一些问题是是有很强的共识的。

借地回复。您两天前 我的信息今天才到,而且那篇文章我没有权限看到。根据文章的标题和您提出的问题,我大致猜测了一下事由,尝试回复和探讨一下。对于二次 clone 后再分享,要拆开,二次 clone 没问题,再分享会因为缺少授权而受到法律限制。在理论法律环境下,可能会因为不满足立案条件或难以评估损失而无法追责。现实中,口袋罪。我不是律师,信口开河,当不得真。

似乎可以理解为增加重复性成本?受教!感谢!祝好!

感谢大佬指点。
另,长见识了才知道还有口袋罪这么个说法…

17 年时候学习 pyspider 框架时候练手爬过, 爬了 1200w+的页面,基本没感受到反爬😂…

别光爬啊,多用用我司产品啊。再爬就给你们爬倒闭了呀

看看我的这个 Web 端反爬虫方案 : https://github.com/FantasticLBP/Anti-WebSpider

可以的

哈哈 都过时了

哎吆。。

获取 cookie 很麻烦,需要真实的浏览器环境才行。

用 puppeteer 呀

他们客户端类似于 https 加密 好像没做反爬

你说的还是大众点评吗?

哈哈哈,现在互联网数据不都是这样搞嘛 大家都心知肚明

哦豁,还有这种操作,可以尝试一下啊

我碰到过必须开启 JavaScript 的网站,只能用 selinum 搞。

试试 pyppeteer 吧,要慢慢了解。不过 selenium 更大众化啦

puppeteer 慢呀 高并发需求

已 star,考虑用 crawlab 来运行一下,https://github.com/tikazyq/crawlab

不是,一个需要登录的购物网站,我需要做下单

类似 Gerapy 的可视化工具嘛?看起来不错,已 star。

可以告诉下地址嘛,我也试试啦。

js 这种扣出相关函数算出符合数据就行了。无规律给脏数据就很麻烦了。

这垃圾网站,别说爬虫了。。。人去看都费劲。。。
用 app 的接口爬还行

反爬只能增加爬虫成本 并不能杜绝

对的,大部分靠这种办法都能解决。

哈哈,有点画面感哦

对的

crawlab 不错的样子,要是爬虫脚本能分享就好了

大佬歪个楼……我想请问一下你是怎么提升爬虫技术水平的

我是一开始是使用 pyspider 爬取一些网站,然后对爬虫开始感兴趣,然后看书敲代码,学 scrapy 框架。不过遇到反爬厉害一点的网站就只会用 selenium+代理池强行怼……所以想问问有什么继续进阶的方向。

正在考虑这个功能,不过是个大功能,可以关注一下,近期会考虑开发

参考下神箭手 他们家做的挺不错的了

是不是必须有代理池才能玩

平心而论,感觉自己还比较菜。
简单说:实践,实践,多实践。刷书后,多敲代码巩固,不管书上内容对个人来说多么通俗易懂,你不上手永元不知 Bug 所在。该过程可以完善你的知识框架。进阶的方向有很多:App,增量式,分布式( rabbit,celery 等),集群,大数据等,到时候自己决定。

小爬虫,便宜的付费代理可以搞一下

#16 我的理解是对数字做了一次自定义的加密,但是前端解密肯定是在 js 的啊,爬虫可以找到这段 js,把你的算法解出来

哈哈哈哈,笑死我了。

我爬的那个网站是先检测浏览器是否启用 js,然后服务端负责跳转到不同页面。要是用的是 react,node,vue 之类的还倒好搞。

试一下,看看性能跟 selinum 比咋样。

大众点评虽然爬起来比较麻烦,不过还好吧

最麻烦的我感觉是天猫淘宝的搜索页

说实在的,啥时候有基于人工智能的爬虫.

你说的是基于登录界面的抓取吗?

爬虫的趋势在向智能化系统方面发展,不过最终留下来的肯定是大虫啦

淘宝?我正常使用都显示不了。

问一下计算偏移量的公式在那个文件可以找到呢

可以的,数字的偏移量计算比较固定,文字的偏移量计算比较多变,我在 md 文档里面有说明,你可以看下

可以看下这个图,我也刚尝试爬虫,但是觉得这个图让我更好的理解了爬虫与反爬虫的思路
http://www.bituplink.com/python-crawler-study-six-level-graph.html

谢谢您的推荐和分享!祝好!

楼主你好,我是一个学生,最近在做一个社会调查,需要一个市级城市的餐饮数据,自己不是学编程专业的,对于大众点评这种有反爬虫网站实在是力不从心,您能帮我爬取一份数据么,如果可以,可以联系我 QQ:NjIwMDAwMjY1,万分感谢.

第一次见全英文扣扣号

BASE64 编码

这个就有点骚了,也不给点提示

回到顶部