一、 引言:一场注定痛苦的跋涉——传统爬虫的“绝望”开局

        一天,你的老板/业务方轻描淡写地说:“小张,帮我把淘宝上‘白酒’的商品数据抓下来,做个分析。于是你打开了淘宝网页,搜索“白酒”,打开F12,复制cURL为Python代码,满心以为大功告成,可是事实却是:运行代码,返回的不是梦寐以求的JSON数据,而是一堆乱码、错误信息,或者更可怕的——一个需要破解的加密字符串

        面对淘宝这种级别的对手,传统的requests方案从一开始就是一场硬仗,而我们接下来将展示一种截然不同的、更高级的战术。


二、 传统方案剖析:深入“加密迷宫”

        “如下述所示,当我们复制CURL为py代码后,得到的代码是这样的:

import requests


headers = {
    "^accept": "*/*^",
    "^accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6^",
    "^referer": "https://uland.taobao.com/sem/tbsearch?bc_fl_src=tbsite_T9W2LtnM^&channelSrp=bingSomama^&clk1=343ce7d3ea06de2cf1a203e8562d1eed^&commend=all^&ie=utf8^&initiative_id=tbindexz_20170306^&keyword=^%^E7^%^99^%^BD^%^E9^%^85^%^92^&localImgKey=^&msclkid=b560bfdb58ff1ed40cc3d708f566da4d^&page=1^&preLoadOrigin=https^%^3A^%^2F^%^2Fwww.taobao.com^&q=^%^E7^%^99^%^BD^%^E9^%^85^%^92^&refpid=mm_2898300158_3078300397_115665800437^&search_type=item^&sourceId=tb.index^&spm=tbpc.pc_sem_alimama^%^2Fa.search_manual.0^&ssid=s5-e^&tab=all^",
    "^sec-ch-ua": "^\\^Chromium^^;v=^\\^140^^, ^\\^Not=A?Brand^^;v=^\\^24^^, ^\\^Microsoft",
    "^sec-ch-ua-mobile": "?0^",
    "^sec-ch-ua-platform": "^\\^Windows^^^",
    "^sec-fetch-dest": "script^",
    "^sec-fetch-mode": "no-cors^",
    "^sec-fetch-site": "same-site^",
    "^user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0^"
}
cookies = {
    "^thw": "cn",
    "xlly_s": "1",
    "cna": "2L0aH3R..........R230EH",
    "3PcFlag": "1758...........593",
    "t": "94798df.................2383ef28d",
    "cookie2": "1cac.................c7486",
    "_tb_token_": "feef...............ee",
    "mtop_partitioned_detect": "1",
    "_m_h5_tk": "c79471ad485fe3...............1758710204340",
    "_m_h5_tk_enc": "d3940c3f319b...............46e40791",
    "tfstk": "gqbnbr1YcM-.......................................1-PXwtfJRuHui1pJgW7DcThaM8G4jmZ01_iPCPR70iWYCOMHYIgNTXQ0fHQs5m4NHR6OKFgs0iWYCOMH5Vi0kte1B9A.",
    "isg": "BHNzNP....................y3lTKg19i^"
}
url = "^https://h5api.m.taobao.com/h5/mtop.relationrecommend.wirelessrecommend.recommend/2.0/"
params = {
    "jsv": "2.7.2^",
    "appKey": "12574478^",
    "t": "1758703041333^",
    "sign": "08bbd88b7905c3f4f41bd302d5be88ef^",
    "api": "mtop.relationrecommend.wirelessrecommend.recommend^",
    "v": "2.0^",
    "type": "jsonp^",
    "dataType": "jsonp^",
    "callback": "mtopjsonp14^",
    "data": "^%^7B^%^22appId^%^22^%^3A^%^2243356^%^22^%^2C^%^22params^%^22^%^3A^%^22^%^7B^%^5C^%^22device^%^5C^%^22^%^3A^%^5C^%^22HMA-AL00^%^5C^%^22^%^2C^%^5C^%^22isBeta^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22grayHair^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22from^%^5C^%^22^%^3A^%^5C^%^22nt_history^%^5C^%^22^%^2C^%^5C^%^22brand^%^5C^%^22^%^3A^%^5C^%^22HUAWEI^%^5C^%^22^%^2C^%^5C^%^22info^%^5C^%^22^%^3A^%^5C^%^22wifi^%^5C^%^22^%^2C^%^5C^%^22index^%^5C^%^22^%^3A^%^5C^%^224^%^5C^%^22^%^2C^%^5C^%^22rainbow^%^5C^%^22^%^3A^%^5C^%^22^%^5C^%^22^%^2C^%^5C^%^22schemaType^%^5C^%^22^%^3A^%^5C^%^22auction^%^5C^%^22^%^2C^%^5C^%^22elderHome^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22isEnterSrpSearch^%^5C^%^22^%^3A^%^5C^%^22true^%^5C^%^22^%^2C^%^5C^%^22newSearch^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22network^%^5C^%^22^%^3A^%^5C^%^22wifi^%^5C^%^22^%^2C^%^5C^%^22subtype^%^5C^%^22^%^3A^%^5C^%^22^%^5C^%^22^%^2C^%^5C^%^22hasPreposeFilter^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22prepositionVersion^%^5C^%^22^%^3A^%^5C^%^22v2^%^5C^%^22^%^2C^%^5C^%^22client_os^%^5C^%^22^%^3A^%^5C^%^22Android^%^5C^%^22^%^2C^%^5C^%^22gpsEnabled^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22searchDoorFrom^%^5C^%^22^%^3A^%^5C^%^22srp^%^5C^%^22^%^2C^%^5C^%^22debug_rerankNewOpenCard^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22homePageVersion^%^5C^%^22^%^3A^%^5C^%^22v7^%^5C^%^22^%^2C^%^5C^%^22searchElderHomeOpen^%^5C^%^22^%^3A^%^5C^%^22false^%^5C^%^22^%^2C^%^5C^%^22search_action^%^5C^%^22^%^3A^%^5C^%^22initiative^%^5C^%^22^%^2C^%^5C^%^22sugg^%^5C^%^22^%^3A^%^5C^%^22_4_1^%^5C^%^22^%^2C^%^5C^%^22sversion^%^5C^%^22^%^3A^%^5C^%^2213.6^%^5C^%^22^%^2C^%^5C^%^22style^%^5C^%^22^%^3A^%^5C^%^22list^%^5C^%^22^%^2C^%^5C^%^22ttid^%^5C^%^22^%^3A^%^5C^%^22600000^%^40taobao_pc_10.7.0^%^5C^%^22^%^2C^%^5C^%^22needTabs^%^5C^%^22^%^3A^%^5C^%^22true^%^5C^%^22^%^2C^%^5C^%^22areaCode^%^5C^%^22^%^3A^%^5C^%^22CN^%^5C^%^22^%^2C^%^5C^%^22vm^%^5C^%^22^%^3A^%^5C^%^22nw^%^5C^%^22^%^2C^%^5C^%^22countryNum^%^5C^%^22^%^3A^%^5C^%^22156^%^5C^%^22^%^2C^%^5C^%^22m^%^5C^%^22^%^3A^%^5C^%^22pc_sem^%^5C^%^22^%^2C^%^5C^%^22page^%^5C^%^22^%^3A2^%^2C^%^5C^%^22n^%^5C^%^22^%^3A48^%^2C^%^5C^%^22q^%^5C^%^22^%^3A^%^5C^%^22^%^25E7^%^2599^%^25BD^%^25E9^%^2585^%^2592^%^5C^%^22^%^2C^%^5C^%^22qSource^%^5C^%^22^%^3A^%^5C^%^22url^%^5C^%^22^%^2C^%^5C^%^22pageSource^%^5C^%^22^%^3A^%^5C^%^22tbpc.pc_sem_alimama^%^2Fa.search_manual.0^%^5C^%^22^%^2C^%^5C^%^22tab^%^5C^%^22^%^3A^%^5C^%^22all^%^5C^%^22^%^2C^%^5C^%^22pageSize^%^5C^%^22^%^3A^%^5C^%^2248^%^5C^%^22^%^2C^%^5C^%^22totalPage^%^5C^%^22^%^3A^%^5C^%^22100^%^5C^%^22^%^2C^%^5C^%^22totalResults^%^5C^%^22^%^3A^%^5C^%^22234413^%^5C^%^22^%^2C^%^5C^%^22sourceS^%^5C^%^22^%^3A^%^5C^%^220^%^5C^%^22^%^2C^%^5C^%^22sort^%^5C^%^22^%^3A^%^5C^%^22_coefp^%^5C^%^22^%^2C^%^5C^%^22filterTag^%^5C^%^22^%^3A^%^5C^%^22^%^5C^%^22^%^2C^%^5C^%^22service^%^5C^%^22^%^3A^%^5C^%^22^%^5C^%^22^%^2C^%^5C^%^22prop^%^5C^%^22^%^3A^%^5C^%^22^%^5C^%^22^%^2C^%^5C^%^22loc^%^5C^%^22^%^3A^%^5C^%^22^%^5C^%^22^%^2C^%^5C^%^22start_price^%^5C^%^22^%^3Anull^%^2C^%^5C^%^22end_price^%^5C^%^22^%^3Anull^%^2C^%^5C^%^22startPrice^%^5C^%^22^%^3Anull^%^2C^%^5C^%^22endPrice^%^5C^%^22^%^3Anull^%^2C^%^5C^%^22p4pIds^%^5C^%^22^%^3A^%^5C^%^22945232213176^%^2C965910341311^%^2C978002414393^%^2C966604414122^%^2C958245836960^%^2C962373167468^%^2C893616693042^%^2C969221670452^%^2C977356735767^%^2C978228890394^%^2C959241164295^%^2C962789360955^%^2C923687409392^%^2C958661543426^%^2C975529384073^%^2C961655943684^%^2C951229679087^%^2C971171731048^%^2C977237145747^%^2C943561873565^%^2C957895783991^%^2C976460770060^%^2C914302099889^%^2C938100459162^%^2C920226253623^%^2C943698766517^%^2C914556336577^%^2C973146408981^%^2C970950592456^%^2C966236143796^%^2C916977564849^%^2C973847175830^%^2C974359906141^%^2C942255685960^%^2C971310443026^%^2C977852093849^%^2C969284111354^%^2C918542758380^%^2C937594221668^%^2C939293708929^%^2C969790551666^%^2C971401579814^%^2C969594642050^%^2C942067613325^%^2C913860274501^%^2C954399773369^%^2C976609854033^%^2C952986464308^%^5C^%^22^%^2C^%^5C^%^22categoryp^%^5C^%^22^%^3A^%^5C^%^22^%^5C^%^22^%^2C^%^5C^%^22myCNA^%^5C^%^22^%^3A^%^5C^%^222L0aH3RUtBIBASQOAwR230EH^%^5C^%^22^%^2C^%^5C^%^22clk1^%^5C^%^22^%^3A^%^5C^%^22343ce7d3ea06de2cf1a203e8562d1eed^%^5C^%^22^%^2C^%^5C^%^22refpid^%^5C^%^22^%^3A^%^5C^%^22mm_2898300158_3078300397_115665800437^%^5C^%^22^%^7D^%^22^%^7D^"
}
response = requests.get(url, headers=headers, cookies=cookies, params=params)

print(response.text)
print(response)

        让我们来逐一分析这个代码里面的天坑:

  • cookies 地狱t_m_h5_tk_tb_token_等,每一个都可能由之前的请求生成,需要维护会话,且有效期极短。

  • sign 签名:这是核心加密点。sign: "08bbd88b7905c3f4f41bd302d5be88ef"这个参数是动态生成的,通常由token时间戳tAPI参数data等通过一套未知的算法计算得出。逆向此算法是最大的技术壁垒。

  • data 参数:本身就是一个URL编码后的JSON字符串,里面又包含了数十个字段(devicebrandpageq等),很多字段含义不明,缺一不可。

  • t 时间戳:必须与sign匹配,服务器会校验。

        也就是说,为了成功发起一次请求,你需要:

  1. 模拟整个登录流程,获取初始cookies

  2. 维护cookies的有效性。

  3. 逆向出sign的加密算法(可能是MD5、SHA,但更可能是自定义复杂算法)。

  4. 正确构造庞大的data参数。

        注意:这还只是第一页。翻页时,pagesignt、乃至cookies可能都要变。你真的愿意把宝贵的时间花在和这些加密参数斗智斗勇上吗?

        所以接下来,本文重点讲述如何使用自动化爬虫去更简单有效的获取地狱级难度的加密网站


三、 降维打击:DrissionPage 的“大道至简”

        在深入那个令人望而生畏的“加密迷宫”之后,是时候请出我们今天的“破壁人”—— DrissionPage 了。它带来的是一种思路上的根本性转变。

1. 什么是 DrissionPage?—— 不是另一个 Selenium

        首先,请允许我给出一个精准的定义:

DrissionPage® 是一个基于 Python 的网页自动化工具。它既能控制浏览器,也能收发数据包,还能把两者合而为一。

        其设计目标是兼顾浏览器自动化的便利性和 requests 的高效率。正因为如此,DrissionPage 本质上是一个智能的、融合模式的网页自动化库

        它的“智能”体现在:开发者可以根据场景,自主或由库智能判断选择最佳工作模式:

  • 浏览器模式:用于处理复杂动态渲染、需要执行JavaScript交互(如点击、输入)的页面。

from DrissionPage import ChromiumPage#浏览器模式
from DrissionPage import ChromiumOptions#传输配置
  • 数据包模式:基于 requests,用于高速收发网络请求,处理静态接口。

from DrissionPage import SessionPage #数据包模式,类似于requests
from DrissionPage import SessionOptions #传输配置

但本文的重点在于展示其“浏览器模式”如何对复杂反爬实现降维打击。 我们将通过模拟浏览器,直接获取渲染后的页面内容,从而绕过所有前端加密和签名逻辑

2. 核心理念:绕过加密,直取结果

        面对淘宝复杂的接口加密,DrissionPage 的解决方案堪称“大道至简”:

我们不需要去理解淘宝的防御系统(签名、令牌)是如何工作的。我们只需要让淘宝的服务器认为这是一个来自真实浏览器的访问请求即可。

        当淘宝服务器接收到一个看似来自 Chrome 浏览器的请求时,它会心甘情愿地将已经渲染好的、包含所有商品信息的 HTML 页面发送过来。我们要做的,只是从这个“所见即所得”的页面中提取明文信息。

        我们可以做一个生动的比喻:

        使用 requests,就像是你自己下厨。你必须亲自去菜市场(分析网络请求)、挑选食材(构造参数)、学习每种食材的处理方法(逆向加密算法),最后才能做出一道菜。不同的网站就像不同的菜系,你需要不断学习新做法。

        而使用 DrissionPage,则像是聘请了一位专业的全能主厨。你只需告诉他“我想吃这个”(目标网址),它就会自动完成采购、处理、烹饪的所有流程,直接为你端上“美味佳肴”(渲染好的页面数据)。你无需关心背后的复杂工艺。

  四、 实战对比:从“地狱”到“天堂”的初体验

        现在,让我们用代码来直观感受这种“降维打击”。还记得之前那几十行令人崩溃的配置吗?用 DrissionPage,实现同样的页面访问并且获取到初始json数据,只需要几行代码:

from DrissionPage import ChromiumPage # 导入库

page = ChromiumPage()  # 创建页面对象

page.listen.start("/h5/mtop.relationrecommend.wirelessrecommend.recommend/2.0/") #监听包含商品json信息的API

page.get("https://uland.taobao.com/sem/tbsearch?bc_fl_src=tbsite_T9W2LtnM&channelSrp=bingSomama&clk1=343ce7d3ea06de2cf1a203e8562d1eed&commend=all&ie=utf8&initiative_id=tbindexz_20170306&keyword=%E7%99%BD%E9%85%92&localImgKey=&msclkid=b560bfdb58ff1ed40cc3d708f566da4d&page=1&preLoadOrigin=https%3A%2F%2Fwww.taobao.com&q=%E7%99%BD%E9%85%92&refpid=mm_2898300158_3078300397_115665800437&search_type=item&sourceId=tb.index&spm=tbpc.pc_sem_alimama%2Fa.search_manual.0&ssid=s5-e&tab=all") #访问“白酒”的搜索网站

orig_json = page.listen.wait().response.body  #获取初始json

print(orig_json)



        输出结果(部分展示):

        有了初始json后,就可以通过后续操作从该原始数据中提取出我们想要的任何字段了

        接下来让我们详细的来解释这个示例代码:

        第1-2行:与之前相同,初始化浏览器。

        第3行:page.listen.start('...'):这是整个技巧的核心。

page.listen.start("/h5/mtop.relationrecommend.wirelessrecommend.recommend/2.0/") 

  page.listen 是 DrissionPage 的网络监听器。.start() 方法开始监听。其参数是一个字符串,用于匹配浏览器发起的网络请求的 URL

        这一行的作用是:告诉 DrissionPage:“请帮我盯着所有网络请求,一旦发现哪个请求的 URL 里包含这个字符串,立刻把它‘抓住’!”

   '/h5/mtop.relationrecommend...' 这个路径,就是通过浏览器开发者工具的“网络(Network)”面板找到的、淘宝用来传输商品列表数据的 API 接口的特征字符串

        如何找到该API?

        第4行:

        打开并访问目标网站,这里指‘白酒商品’搜索结果,浏览器开始加载淘宝搜索页面。当页面渲染时,它会自动向步骤2中我们监听的那个 API 接口发起请求,以获取商品数据。

        第5行:

orig_json = page.listen.wait().response.body

          重点: page.listen.wait()

   wait() 方法会阻塞程序,直到监听器成功捕获到第一个匹配我们条件的请求。

    .response.body 直接获取这个请求响应体(Response Body) 的内容(json/dict)

        这行代码的含义是:“等一下,直到抓到我们想要的那个数据接口的响应,然后把里面的原始数据取出来。”

        最后,打印获取到的数据。你会发现,这不再是 HTML,而是结构清晰、包含所有商品信息的原始 JSON 数据!无需任何解密,因为浏览器已经帮你完成了身份验证等所有前置工作。

        上述代码仅仅展示获取单页数据的方法,如果需要实现全自动化,下述提供一个作者的思路:(此代码不做详细赘述,有兴趣者请自行前往官网研究

from ....

page =  ...

page.listen.start(...) #监听目标API

page.get(...)  #访问目标网站

whlie True:
    
    orig_datas = page.listen.wait().response.body  #截取监听数据

    btn = page.ele("翻页的具体元素")  #翻页按钮

    if btn.attr("翻页中止条件"):  #翻页(循环)中止条件

        break

    btn.click()  #模拟点击翻页
   
     time.sleep(1)
    


       

五、 核心对比总结:降维打击的维度

让我们回顾一下这个方案的精妙之处,并与传统方法进行对比:

对比维度 传统 Requests 方案 DrissionPage 方案 降维解读
开发心智 逆向工程师:陷入加密参数的泥潭 使用者:关注业务逻辑和数据提取 从“造轮子”到“开车”
代码复杂度 :上百行配置,高度脆弱 :<20行核心逻辑,健壮性强 复杂度降低一个数量级
维护成本 极高:接口或加密方式一变,前功尽弃 :只要网页视觉效果不变,代码就有效 抗击变化能力强
技术门槛 :需深厚JS逆向功底 :会Python和基础CSS选择器即可 让更多人能解决复杂问题
成功概率 不确定:可能卡在某个加密参数上 :所见即所得,成功率逼近100% 从“可能行”到“一定行”

这个例子完美诠释了“降维打击”
        传统方法费尽心力去模拟的加密通信,在 DrissionPage 的方案下被完全绕过了。我们利用浏览器作为“前端工程师”,让它去搞定所有复杂的认证和通信,而我们作为“后端数据收割者”,只需轻松地拿走最终成果。

        这种方法兼具了 浏览器模式的真实性(绕过反爬)和 API 接口的高效性(直接获取结构化数据),是 DrissionPage 融合模式的最佳实践之一。

六、 结论与适用场景

        结论:对于反爬虫机制严密的现代Web应用(如淘宝、微博、B站),DrissionPage代表的“浏览器自动化”思路,在开发效率、成功率和可维护性上,对传统的“接口逆向”思路实现了彻底的降维打击

        适用场景:        

  • 快速验证与爬取:需要快速拿到数据,不想纠缠于加密细节。

  • 动态内容丰富的网站:页面由JavaScript动态渲染。

  • 需要模拟交互的操作:如登录、点击、下拉等。

        最后提醒:能力越大,责任越大。请务必遵守robots.txt,设置访问间隔,将技术用于合法的商业分析和学习目的。

      声明与致谢:本文旨在交流 DrissionPage 这一优秀工具的使用思路。笔者作为一名仍在学习阶段的在校学生,深知技术视野有限,行文中难免有疏漏或不妥之处。若您发现任何问题,或是有更佳实践,恳请不吝赐教,在评论区留言交流。对 DrissionPage 感兴趣的朋友,强烈建议访问其官方文档或项目主页进行深入探索。

        最后的最后,如果各位看官老爷有爬虫需求,欢迎联系作者~ 技术尚可,价格好说,就当赞助一下学生的咖啡钱啦!😄

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐