如何用Python爬取iframe内动态表格的全量30万行数据
中国海关站点30万全量数据Python抓取可行方案
核心实现逻辑
别上来就用自动化工具逐页翻200条,1500页爬完效率极低还容易被封。这类政府统计站点的导出、分页限制基本都是前端写死的,后端很少做严格的参数拦截,只要维持住校验通过的合法会话,直接改接口参数就能拿全量数据。
- 第一步:会话初始化与校验
用requests.Session()创建持久化会话,所有请求都走这个会话自动带cookie,不要用零散的requests请求。
先访问目标站点拿初始cookie,再模拟两次维度选择的请求——打开浏览器开发者工具,正常点两次选维度的按钮,看Network里对应的请求地址、参数,直接照搬就行,请求头里的UA、Referer要和你浏览器里的一致,别用requests默认的UA,容易被拦。
验证码部分不用搞复杂的深度学习方案,两种处理方式:要么用ddddocr库做本地识别,这类站点的验证码都是简单的数字字母组合,准确率能到95%以上;要是识别报错率高,就写几行代码把拿到的验证码图片弹出来手动输入,一次校验通过后,cookie有效期内不用再重复验。注意:验证码图片的请求必须用同一个Session发,不然验证码和会话不绑定,输对了也会提示校验失败。
- 第二步:定位数据接口
校验通过进入数据表格页后,在开发者工具里过滤XHR/Fetch请求,手动翻一页表格,找返回表格数据的接口,重点看参数里的分页字段,一般是pageNum、pageSize、offset、limit这类命名。自带导出功能限1万条,本质是前端调用导出接口时把limit参数写死成了10000,后端大概率没卡这个值。 - 第三步:全量数据拉取,两种方案按需选
- 接口直连方案(效率最高,优先选)
找到数据查询或者CSV导出的接口,先试直接把limit参数改成300000发请求,如果能正常返回全量就直接存;如果后端做了单次请求上限拦截,就分30次请求,每次偏移1万条拉1万条数据,最后本地拼接成完整文件就行,比逐页爬200条快十多倍。
参考代码片段:import requests import csv import ddddocr # 初始化持久会话 sess = requests.Session() sess.headers.update({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "Referer": "http://43.248.49.97/indexEn" }) # 访问首页拿初始cookie sess.get("http://43.248.49.97/indexEn") # 验证码识别,接口地址替换成你抓包拿到的实际地址 captcha_resp = sess.get("http://43.248.49.97/xxx/captcha") ocr = ddddocr.DdddOcr(show_ad=False) captcha_code = ocr.classification(captcha_resp.content) # 要是识别不准就把下面这行放开,手动输验证码 # from PIL import Image # import io # Image.open(io.BytesIO(captcha_resp.content)).show() # captcha_code = input("请输入验证码:") # 提交两次维度选择+验证码校验,接口地址和参数替换成抓包拿到的内容 # sess.post("http://43.248.49.97/xxx/dim1", data={"dim_code": "你选的一级维度值"}) # sess.post("http://43.248.49.97/xxx/dim2", data={"dim_code": "你选的二级维度值", "captcha": captcha_code}) # 分块拉取全量数据 all_rows = [] chunk_size = 10000 # 按站点自带的单次导出上限分块,避免触发拦截 total_count = 300000 for offset in range(0, total_count, chunk_size): resp = sess.post( "http://43.248.49.97/xxx/data/list", # 替换成实际数据接口地址 data={ "offset": offset, "limit": chunk_size, # 其余筛选参数完全照搬浏览器正常请求的内容 } ) # 按接口实际返回格式解析数据 chunk_rows = resp.json()["data"]["records"] all_rows.extend(chunk_rows) # 保存为本地CSV,用utf-8-sig编码避免Excel打开乱码 with open("customs_full_data.csv", "w", encoding="utf-8-sig", newline="") as f: writer = csv.DictWriter(f, fieldnames=all_rows[0].keys()) writer.writeheader() writer.writerows(all_rows) - 浏览器自动化兜底方案(适合接口有动态签名不好逆向的情况)
要是接口参数带动态加密签名,逆向成本太高,就用playwright做自动化模拟,比Selenium稳定不用手动配浏览器驱动。启动浏览器后手动/自动过验证码,选好维度,定位到iframe里的表格和分页按钮,自动翻页抓取每一页的表格内容追加到结果集。1500页的话每次翻页加1-2秒的随机延时,半小时左右就能爬完,不会触发反爬。
- 接口直连方案(效率最高,优先选)
- 避坑提醒
- 所有请求必须在同一个会话上下文里,cookie丢了就会跳回验证页面,之前的操作全白费
- 别一开始就把请求块大小设成30万,很容易触发后端超时或者IP拦截,按1万的块长拉最稳
- 保存文件别用utf-8编码,不然Excel打开中文全是乱码,用utf-8-sig
- 爬的时候别请求太频繁,政府站点服务器带宽和性能都一般,频率太高容易把IP封了
内容的提问来源于stack exchange,提问作者A Martinez
相关产品推荐
相关产品推荐

