Python爬虫实战:破解巨量星图反爬,高效获取达人数据

📅 2026/8/24 4:06:54
Python爬虫实战:破解巨量星图反爬,高效获取达人数据
1. 项目概述从零到一搞定巨量星图数据做营销投放、达人分析或者市场研究的朋友对“巨量星图”这个平台肯定不陌生。它是字节跳动旗下官方的达人营销平台汇聚了抖音、今日头条等海量创作者资源。无论是想找合适的达人合作还是分析某个垂类的达人生态、报价趋势星图上的数据都是最直接、最权威的参考。但问题来了平台本身并没有提供批量导出数据的接口手动一个个去翻、去记效率低到令人发指而且数据维度也不够结构化。这时候Python爬虫就成了我们的“瑞士军刀”。这个项目的核心目标就是利用Python自动化地、批量化地从巨量星图平台获取我们需要的达人数据比如达人昵称、粉丝量、互动数据、报价区间、所属类别、联系方式如果可见等等。这听起来像是一个典型的爬虫任务但实际操作起来你会发现它远不止一个简单的requests.get()那么简单。巨量星图作为字节跳动的核心商业产品其前端交互复杂反爬机制也相当完善直接请求接口往往需要处理动态参数、签名验证等问题。所以这个项目更像是一场“攻防战”。我们需要根据不同的数据需求和反爬强度灵活组合多种技术方案。从最基础的模拟登录获取Cookie到使用Selenium模拟真人操作再到更底层的抓包分析真实API每一步都充满了挑战和技巧。接下来我就结合自己多次实战的经验把这套从易到难、从浅入深的完整方案拆解给你看让你不仅能拿到数据更能理解背后的原理和避坑要点。2. 核心思路与技术选型因地制宜的爬取策略面对一个像巨量星图这样的大型商业平台没有一种方法可以通吃所有场景。我们的技术选型必须基于目标数据的可达性和项目的可持续性来权衡。下面这张表清晰地对比了三种主流方案的优劣和适用场景方案核心工具优点缺点适用场景方案ACookie直连requests,curl速度极快资源消耗低效率高。获取有效Cookie门槛高易过期需处理签名等动态参数。对API结构非常熟悉能稳定获取登录态需要高频、快速抓取少量已知接口。方案B浏览器自动化selenium,undetected-chromedriver绕过前端加密逻辑模拟真人操作通用性强。速度慢资源占用高内存/CPU容易被检测到自动化特征。页面交互复杂接口参数动态生成且难以逆向需要触发点击、滚动等操作不追求极致速度。方案C抓包分析Fiddler/Charles/浏览器开发者工具能捕获最真实的网络请求直接获取API URL和参数格式是前两种方案的基础。需要手动分析对于参数加密复杂的接口仍需结合逆向工程。所有场景的第一步。用于侦察、分析接口规律为方案A或B提供关键信息。在实际项目中我通常会采用“抓包分析先行Selenium攻坚Requests优化”的混合策略。具体流程是侦察阶段使用Fiddler或浏览器开发者工具手动在星图网站上操作一遍搜索、筛选、翻页观察并记录下关键的数据请求通常是XHR/Fetch请求。攻坚阶段如果发现请求参数带有_signature、as、cp等一看就是后端生成的加密参数直接逆向JS计算成本很高。此时最稳妥的方式就是使用Selenium配合undetected-chromedriver这类反反爬工具启动一个真实的浏览器环境让浏览器自己去执行JS生成这些参数我们直接从浏览器发起的请求中拦截或等待页面渲染后提取数据。优化阶段当通过Selenium成功跑通流程后我们可以仔细分析它发出的请求。有时会发现某些加密参数在一定时间内或同一会话中是固定或可推算的。这时我们就可以尝试用Requests库来模拟这些请求从而大幅提升爬取速度实现从“自动化操作”到“自动化接口调用”的飞跃。注意无论采用哪种方案都必须严格遵守网站的robots.txt协议并控制请求频率避免对目标服务器造成过大压力。过量、高频的请求不仅可能导致你的IP被封也可能违反相关法律法规和使用条款。建议在请求间添加随机延时如time.sleep(random.uniform(1, 3))并尽量在非高峰时段运行脚本。3. 环境准备与核心工具详解工欲善其事必先利其器。在开始编码之前我们需要搭建一个稳定、高效的开发环境并理解每个工具扮演的角色。3.1 Python环境与基础库首先确保你安装了Python3.7及以上版本推荐。我们将使用pip安装以下核心库requests: HTTP库的绝对主力用于发送HTTP请求。方案A的核心。pip install requestsselenium: 浏览器自动化工具。方案B的核心。pip install seleniumundetected-chromedriver: 一个非常强大的第三方库它能自动下载和配置ChromeDriver并修改Selenium的特征使其更难以被网站检测为自动化脚本。在应对星图这类平台时几乎是Selenium方案的必备品。pip install undetected-chromedriverpandas: 数据处理和分析库。抓取到的数据通常是JSON或列表形式用Pandas可以方便地清洗、分析和导出为Excel或CSV。pip install pandaslxml / beautifulsoup4: HTML解析库。当Selenium渲染出页面后或者某些接口返回HTML片段时我们需要用它来提取其中的结构化数据。pip install lxml beautifulsoup43.2 浏览器与驱动管理如果你选择Selenium方案需要对应版本的Chrome浏览器和ChromeDriver。这是新手最容易踩坑的地方之一。查看Chrome版本在浏览器地址栏输入chrome://settings/help查看版本号例如123.0.6312.106。下载ChromeDriver访问 ChromeDriver官网 或国内镜像站下载与你的Chrome浏览器主版本号完全相同的驱动例如Chrome 123对应ChromeDriver 123。放置驱动将下载的chromedriverWindows是.exe文件放在一个固定目录并将该目录添加到系统的环境变量PATH中。更简单的做法是在Python脚本里指定驱动路径。实操心得我强烈推荐使用undetected-chromedriver库。它不仅能自动管理驱动版本匹配问题其核心价值在于“隐身”能力。普通Selenium启动的浏览器有几十个特征可以被网站检测到如navigator.webdriver属性为true。undetected-chromedriver通过打补丁的方式消除了这些特征极大提高了在严格反爬网站上的成功率。它的基本用法和Selenium几乎一样但启动方式更安全。3.3 抓包工具配置抓包是爬虫的“眼睛”。我主要使用两款工具Fiddler Classic / Charles: 这两款是功能强大的专业抓包工具可以拦截和修改所有经过系统的HTTP/HTTPS流量包括手机端。配置稍复杂需要安装证书并设置代理。它们适合进行深入的请求/响应分析特别是查看加密前的请求体。浏览器开发者工具 (DevTools)最快捷的工具。按F12打开切换到Network网络面板。进行页面操作如点击搜索、翻页所有网络请求都会在这里列出。重点关注XHR或Fetch类型的请求这些通常就是获取数据的API接口。点击某个请求可以查看其Headers请求头、Payload请求参数通常在Payload或Request Body标签页和Response响应。一个关键技巧在DevTools的Network面板中勾选“Preserve log”保留日志这样在页面跳转或刷新时之前的请求记录不会被清空。同时右键点击请求选择“Copy” - “Copy as cURL”可以快速将请求转换为命令行或Pythonrequests代码片段这是从抓包到代码的捷径。4. 实战演练Selenium模拟操作获取数据假设我们的目标是爬取“美妆”类目下粉丝量在100万-500万之间的达人列表及其基础信息。我们将采用Selenium方案因为它能最好地处理复杂的页面交互和动态参数。4.1 初始化隐身浏览器首先我们使用undetected_chromedriver来启动一个“隐身”的Chrome浏览器。import undetected_chromedriver as uc import time from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC options uc.ChromeOptions() # 添加一些常用选项非必须但推荐 # options.add_argument(--disable-blink-featuresAutomationControlled) # options.add_argument(--start-maximized) # 最大化窗口 # 如果你想指定Chrome用户数据目录实现免登录可以取消下面注释需先手动登录一次 # options.add_argument(r--user-data-dirC:\Users\YourName\AppData\Local\Google\Chrome\User Data) # options.add_argument(--profile-directoryDefault) driver uc.Chrome(optionsoptions) wait WebDriverWait(driver, 10) # 设置显式等待最多等10秒重要提示undetected_chromedriver第一次运行时会自动下载匹配的驱动可能需要一点时间。指定user-data-dir是一个高级技巧你可以先手动用这个浏览器打开星图并登录以后脚本启动时就会是已登录状态省去模拟登录的麻烦。但要注意多开时目录冲突问题。4.2 模拟登录与Cookie处理如果没使用用户数据目录我们就需要模拟登录。星图的登录可能涉及滑块验证码完全自动化破解难度和风险都很高。更可行的策略是“半自动化”让脚本打开登录页面并暂停。用户手动扫码或输入账号密码完成登录包括可能的手动滑块验证。脚本检测到登录成功如URL跳转或出现特定元素后再继续执行。# 打开星图登录页 driver.get(https://star.toutiao.com) time.sleep(5) # 等待页面加载 print(请手动在浏览器中完成登录...) input(登录完成后请在控制台按回车键继续...) # 登录后可以获取并保存Cookie供后续requests使用如果后续能破解接口 cookies driver.get_cookies() # 可以将cookies保存为json文件 import json with open(xingtu_cookies.json, w) as f: json.dump(cookies, f) print(Cookie已保存。)4.3 页面导航与数据定位登录成功后我们导航到达人列表页并设置筛选条件。# 假设我们已经登录直接到达人列表页这里URL可能需要根据实际情况调整 list_url https://star.toutiao.com/ability/star/list driver.get(list_url) time.sleep(3) # 等待页面关键元素加载 wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, .category-filter))) # 示例选择类目这里需要根据实际网页的HTML结构来定位元素 # 通常需要点击筛选框然后在弹出的下拉列表中选择。这里用伪代码表示逻辑。 try: category_filter driver.find_element(By.XPATH, //div[contains(text(),选择类目)]) category_filter.click() time.sleep(1) beauty_category driver.find_element(By.XPATH, //li[contains(text(),美妆)]) beauty_category.click() time.sleep(2) # 等待筛选结果加载 except Exception as e: print(f选择类目时出错: {e}) # 可以尝试其他定位方式或者直接通过URL参数筛选 # 示例设置粉丝数筛选同样需要根据实际UI操作 # 可能需要点击“粉丝数”输入框输入范围值。实操心得星图前端的HTML结构和类名可能会频繁变动。不要依赖绝对不变的CSS选择器或XPath。优先使用包含部分文本、相对稳定属性的定位方式如By.XPATH, //button[contains(class, search-btn)]。最可靠的方法是使用浏览器DevTools的检查功能右键点击元素选择“Copy” - “Copy full XPath”或“Copy selector”但也要注意这些生成的路径可能很脆弱。更好的方法是寻找元素特有的>import json def scroll_to_bottom(driver, max_scrolls20): 模拟滚动到底部触发加载更多 last_height driver.execute_script(return document.body.scrollHeight) scroll_attempts 0 while scroll_attempts max_scrolls: driver.execute_script(window.scrollTo(0, document.body.scrollHeight);) time.sleep(random.uniform(2, 4)) # 随机等待模仿人类 new_height driver.execute_script(return document.body.scrollHeight) if new_height last_height: # 可能已加载完毕或需要点击“加载更多”按钮 try: load_more_btn driver.find_element(By.CSS_SELECTOR, .load-more) load_more_btn.click() time.sleep(2) except: break # 没有找到按钮可能真的结束了 last_height new_height scroll_attempts 1 # 执行滚动 scroll_to_bottom(driver) # 现在页面应该包含了大量达人卡片开始提取数据 creator_cards driver.find_elements(By.CSS_SELECTOR, .star-card) # 替换为实际的卡片选择器 data_list [] for card in creator_cards: try: # 提取信息这里的选择器需要你根据实际页面结构调整 name card.find_element(By.CSS_SELECTOR, .name).text # 粉丝数可能包含“万”字需要处理 fans_elem card.find_element(By.CSS_SELECTOR, .fans) fans_text fans_elem.text # 处理“123.4万”这样的字符串 if 万 in fans_text: fans float(fans_text.replace(万, )) * 10000 else: fans int(fans_text.replace(,, )) # 其他字段如互动率、报价、类别等类似方法提取 # ... data_list.append({ name: name, fans: int(fans), # ... 其他字段 }) except Exception as e: print(f提取卡片数据时出错: {e}) continue print(f共提取到 {len(data_list)} 条达人数据。) # 使用pandas保存 import pandas as pd df pd.DataFrame(data_list) df.to_excel(巨量星图达人列表.xlsx, indexFalse)5. 进阶抓包分析直连APISelenium虽然省心但速度是硬伤。如果我们追求效率就必须尝试直连API。这就需要用到前面提到的抓包工具。开启抓包打开Fiddler/Charles或浏览器DevTools的Network面板并保持“Preserve log”开启。操作并观察在星图页面进行筛选、翻页操作。在Network面板中你会看到大量请求。寻找那些返回数据是JSON格式Preview或Response标签页看的请求这些就是数据接口。分析请求点击一个返回达人列表的请求查看其请求URL (Request URL): 通常包含api、list等关键词。请求方法 (Request Method): 通常是GET或POST。请求头 (Request Headers): 重点关注Cookie、Authorization、User-Agent以及一些自定义头如X-Tt-Token、X-Secsdk-Csrf-Token等。这些是身份验证和反爬的关键。请求参数 (Query String Parameters / Form Data / Payload): 如果是GET参数在URL里如果是POST参数在Payload里。仔细查看page页码、size每页大小、category_id类目ID、fans_range粉丝范围等筛选参数。特别注意那些长的、无规律的字符串参数如_signature这通常是服务器验证的加密签名。尝试复现在Python中尝试用requests库模拟这个请求。首先把抓到的Cookie和Headers尤其是User-Agent原样复制过来。import requests import json # 从抓包工具中复制过来的Headers注意替换成你自己的 headers { Accept: application/json, text/plain, */*, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Cache-Control: no-cache, Connection: keep-alive, Cookie: 你的长长的一串Cookie从抓包工具里Copy过来, Pragma: no-cache, Referer: https://star.toutiao.com/, Sec-Fetch-Dest: empty, Sec-Fetch-Mode: cors, Sec-Fetch-Site: same-origin, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36, # 可能还有自定义头如 # X-Tt-Token: ..., # X-Secsdk-Csrf-Token: ..., } # 请求参数也从抓包工具里复制 params { category_id: 1, # 美妆类目ID需要探查 fans_range: 1000000,5000000, page: 1, size: 20, # _signature: ..., # 这个参数很可能需要动态生成 } url https://star.toutiao.com/api/star/list # 示例URL需替换为真实接口 response requests.get(url, headersheaders, paramsparams) if response.status_code 200: data response.json() print(json.dumps(data, indent2, ensure_asciiFalse)) else: print(f请求失败状态码: {response.status_code}) print(response.text)如果请求成功返回了数据那么恭喜你你找到了核心接口。但大概率你会遇到403或400错误提示签名无效。这说明_signature或其他参数是动态加密的。6. 核心难点动态签名参数破解_signature这类参数是爬虫与反爬对抗的核心。它通常是由前端JavaScript根据当前时间、请求参数、用户令牌等计算生成的一个加密字符串用于防止请求被伪造。破解思路有以下几种难度递增寻找规律最简单但可能无效观察多个请求的_signature看它是否在一定时间内不变或者是否只与某几个固定参数有关。对于简单场景可能有效。执行JS计算主流方法使用execjs、PyExecJS或node.js子进程在Python环境中直接执行网页中的JavaScript加密函数。这需要你从网页源码或JS文件中找到生成签名的函数。步骤 a. 在浏览器DevTools的Sources源代码面板或Network网络面板中搜索_signature、sign、encrypt等关键词。 b. 找到包含加密逻辑的JS文件通常是被混淆过的。你需要仔细分析找到入口函数。 c. 将该函数及其依赖的其他函数代码提取出来。 d. 在Python中使用execjs调用这个函数传入相同的参数生成签名。工具execjs库。import execjs # 假设你已经把生成_signature的js代码保存到了sign.js文件中 with open(sign.js, r, encodingutf-8) as f: js_code f.read() ctx execjs.compile(js_code) # 根据js函数需要的参数传入 signature ctx.call(generate_signature, params) params[_signature] signatureRPC调用高级方法使用selenium或puppeteer通过pyppeteer启动一个无头浏览器在页面上下文中直接调用JS函数获取签名然后传递给Python端的requests使用。这种方式结合了Selenium的JS执行能力和requests的高效率。移动端API降维打击有时平台的移动端App或H5页面的API防护较弱。可以尝试抓包手机App需要配置Fiddler/Charles作为手机代理分析其接口可能签名逻辑更简单甚至没有。重要警告逆向和破解加密逻辑可能涉及法律风险务必仅用于个人学习和研究并严格遵守网站的服务条款。如果数据可通过官方API或合作方式获得应优先选择合法途径。7. 数据清洗、存储与优化策略拿到原始数据通常是JSON后工作只完成了一半。7.1 数据清洗与解析API返回的数据可能嵌套很深需要仔细解析。使用Python的字典和列表操作或pandas.json_normalize函数来展平数据。import pandas as pd # 假设api返回的JSON结构如下 sample_response { code: 0, data: { list: [ {star_name: 达人A, fans_count: 1500000, interaction_rate: 5.2%, price_range: 1-2万}, {star_name: 达人B, fans_count: 3200000, interaction_rate: 4.8%, price_range: 3-5万}, # ... ], total: 150 } } if sample_response[code] 0: data_list sample_response[data][list] df pd.DataFrame(data_list) # 重命名列使其更易读 df.rename(columns{ star_name: 达人名称, fans_count: 粉丝数, interaction_rate: 互动率, price_range: 报价区间 }, inplaceTrue) # 清洗“互动率”去掉百分号并转为浮点数 df[互动率] df[互动率].str.rstrip(%).astype(float) / 100.0 # 清洗“粉丝数”确保是整数 df[粉丝数] pd.to_numeric(df[粉丝数], errorscoerce).fillna(0).astype(int) print(df.head())7.2 数据存储根据数据量和使用场景选择存储方式CSV/Excel适合中小规模数据几万条以内方便用Excel打开查看和简单分析。使用df.to_csv(data.csv, indexFalse, encodingutf-8-sig)。SQLite/MySQL/PostgreSQL适合大规模、结构化数据便于复杂查询和增量更新。可以使用sqlalchemy库。MongoDB如果返回的JSON结构非常复杂、多变NoSQL的MongoDB可能更合适。7.3 反爬应对与优化策略IP代理池这是应对IP封锁最有效的手段。你需要准备一批高质量的HTTP/HTTPS代理IP并在请求中随机切换。免费的代理大多不稳定商业代理是更靠谱的选择。import requests from itertools import cycle proxy_list [ http://user:passip1:port, http://user:passip2:port, # ... ] proxy_pool cycle(proxy_list) for i in range(10): proxy next(proxy_pool) try: response requests.get(url, headersheaders, proxies{http: proxy, https: proxy}, timeout5) # 处理响应 break # 成功则跳出循环 except: print(f代理 {proxy} 失败尝试下一个。) continue请求头伪装除了User-Agent还要注意Accept、Accept-Language、Referer等头尽量模拟得跟真实浏览器一样。可以使用fake_useragent库随机生成User-Agent。请求频率控制在请求间加入随机延时模拟人类操作间隔。time.sleep(random.uniform(1, 5))。会话保持使用requests.Session()对象它可以自动处理Cookies保持登录状态比单次请求更高效。错误重试与断点续传网络请求难免失败。实现重试机制如tenacity库和记录已爬取页码/ID的功能确保脚本异常中断后能从断点恢复。8. 常见问题与排查技巧实录在实际操作中你一定会遇到各种各样的问题。这里记录了几个最典型的“坑”和我的解决方法。问题1Selenium脚本被检测弹出验证码或直接拒绝访问。排查检查浏览器是否带有明显的自动化特征。打开chrome://version/查看命令行如果包含--enable-automation或--headless等就容易被识别。解决使用undetected_chromedriver这是首选方案。如果必须用原生Selenium尝试添加更多反检测选项options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_experimental_option(useAutomationExtension, False) options.add_argument(--disable-blink-featuresAutomationControlled)避免使用headless无头模式有头模式更不易被检测。在关键操作如点击、输入前加入随机延时和人类化的鼠标移动轨迹可使用ActionChains稍微移动鼠标。问题2使用requests调用API总是返回403 Forbidden或400 Bad Request。排查Cookie过期检查Cookie是否还有效。重新抓包获取最新的Cookie。签名错误检查_signature、as、cp等参数。对比多个成功请求看这些参数是如何变化的。如果变化无规律基本确定是前端加密生成。请求头缺失对比抓包到的请求头和你代码中的请求头是否漏掉了某些关键头如X-Tt-Token、X-Secsdk-Csrf-Token、Origin、Referer等。参数格式错误检查GET请求的参数是否都在URL里POST请求的data或json参数格式是否正确。特别是时间戳可能是毫秒级13位而非秒级10位。解决按照第6节的方法重点攻克签名参数。如果时间紧迫退而求其次使用Selenium方案。问题3页面元素定位不到抛出NoSuchElementException。排查页面未加载完成在操作元素前增加等待时间。使用WebDriverWait配合expected_conditions是更优雅的方式而不是死板的time.sleep。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By element WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, myDynamicElement)) )iframe框架要操作的元素可能在iframe里面。需要先使用driver.switch_to.frame(frame_reference)切换到对应的iframe中才能定位其中的元素。元素属性已改变网站的UI更新了。需要重新检查元素的选择器。解决使用更健壮的定位策略优先使用ID、name其次是用XPath结合文本和属性。对于动态加载的内容等待其出现再操作。问题4抓取速度太慢尤其是Selenium方案。解决禁用图片和CSS通过ChromeOptions加载浏览器时设置prefs来禁止加载图片和样式表可以大幅提升页面加载速度。prefs {profile.managed_default_content_settings.images: 2} options.add_experimental_option(prefs, prefs)使用无头模式如果确认无头模式不会被检测或已用undetected_chromedriver处理可以加上options.add_argument(--headless)。并行化如果有多账号或代理可以考虑使用concurrent.futures或multiprocessing模块同时运行多个浏览器实例或请求会话处理不同的搜索条件或页码。但要注意账号安全和IP风控。终极优化将Selenium方案作为“侦察兵”和“签名生成器”只用来获取关键的加密参数或初始Cookie后续的数据抓取全部用优化后的requests多线程/异步请求来完成这是速度最快的方案。这个项目从简单的数据获取需求出发深入到了网络协议、浏览器自动化、前端逆向和反爬对抗等多个领域。没有一劳永逸的解决方案唯有根据目标网站的变化不断调整策略。我的经验是保持耐心从抓包分析开始一步步拆解先让Selenium跑起来拿到数据再考虑优化和提速。过程中积累的调试和排查经验其价值往往超过了数据本身。最后再次强调技术用于学习与研究务必合规使用控制请求频率尊重数据版权。