手动构建链接可访问,用urllib调用Super-Pharm API生成下载链接失败
核心思路:模拟完整浏览器会话
站点的动态Header和Cookie属于会话验证机制,硬编码固定值必然失效,必须从访问首页开始建立完整会话,自动处理Cookie和动态生成的字段。
步骤1:改用requests库(比urllib更易维护会话)
requests.Session()会自动维护会话Cookie,省去手动处理的麻烦。示例代码如下:
import requests import re import json # 初始化会话,自动管理Cookie session = requests.Session() # 1. 访问首页,获取初始Cookie与动态参数(如CSRF Token) home_url = "http://prices.super-pharm.co.il/" home_res = session.get(home_url) # 从页面meta标签提取CSRF Token(如果站点使用该验证) csrf_token = re.search(r'<meta name="csrf-token" content="(.*?)">', home_res.text) csrf_token = csrf_token.group(1) if csrf_token else "" # 2. 调用第一个API,获取构建下载链接的参数 first_api_url = "替换为实际第一个API地址" api_headers = { "Accept": "application/json", "X-CSRF-Token": csrf_token, "Referer": home_url, "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" } first_api_res = session.get(first_api_url, headers=api_headers) download_params = first_api_res.json() # 3. 调用第二个API,获取实际下载链接 second_api_url = f"替换为实际第二个API地址?param={download_params['key']}" second_api_res = session.get(second_api_url, headers=api_headers) actual_download_link = second_api_res.json()["download_url"] # 4. 下载gzip文件 gzip_res = session.get(actual_download_link) with open("super_pharm_prices.gz", "wb") as f: f.write(gzip_res.content)
步骤2:用浏览器开发者工具抓包分析完整流程
- 打开Chrome/Firefox开发者工具(F12),切换到Network标签
- 清空现有请求,刷新站点,跟踪从首页到两次API调用再到gzip下载的所有请求
- 重点分析:
- Request Headers:区分固定字段(如
User-Agent、Accept)和动态字段(如X-CSRF-Token、会话Cookie) - Cookie:观察Cookie的生成时机(通常是访问首页时服务器通过
Set-Cookie返回) - 参数传递:两次API调用之间的参数依赖逻辑
- Request Headers:区分固定字段(如
步骤3:坚持用urllib的话,手动维护CookieJar
import urllib.request import http.cookiejar import re import json # 初始化CookieJar保存会话Cookie cookie_jar = http.cookiejar.CookieJar() opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie_jar)) urllib.request.install_opener(opener) # 1. 访问首页获取初始Cookie和动态参数 home_url = "http://prices.super-pharm.co.il/" home_req = urllib.request.Request(home_url) home_res = urllib.request.urlopen(home_req) home_html = home_res.read().decode("utf-8") csrf_token = re.search(r'<meta name="csrf-token" content="(.*?)">', home_html) csrf_token = csrf_token.group(1) if csrf_token else "" # 2. 第一个API请求 first_api_url = "替换为实际第一个API地址" api_headers = { "Accept": "application/json", "X-CSRF-Token": csrf_token, "Referer": home_url, "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" } first_api_req = urllib.request.Request(first_api_url, headers=api_headers) first_api_res = urllib.request.urlopen(first_api_req) download_params = json.loads(first_api_res.read().decode("utf-8")) # 3. 第二个API请求获取下载链接 second_api_url = f"替换为实际第二个API地址?param={download_params['key']}" second_api_req = urllib.request.Request(second_api_url, headers=api_headers) second_api_res = urllib.request.urlopen(second_api_req) actual_link = json.loads(second_api_res.read().decode("utf-8"))["download_url"] # 4. 下载gzip文件 download_req = urllib.request.Request(actual_link, headers=api_headers) download_res = urllib.request.urlopen(download_req) with open("super_pharm_prices.gz", "wb") as f: f.write(download_res.read())
关键注意事项
- 绝不硬编码Cookie/Header:动态字段必须从会话中实时获取,Cookie由会话自动维护,CSRF Token从页面提取
- 严格遵循浏览器请求顺序:必须先访问首页,再调用API,直接请求API会被服务器拒绝
- 使用真实浏览器的
User-Agent:避免被识别为爬虫 - 确认API请求方式:部分API为POST而非GET,抓包时注意核对
Request Method
内容的提问来源于stack exchange,提问作者Dolev Mitz
相关产品推荐
相关产品推荐

