新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python爬虫实战:抓取京东搜索页商品信息、翻页去重与落库

发布时间:2026/9/26 7:23:19来源:尧图网络
Python爬虫实战:抓取京东搜索页商品信息、翻页去重与落库
买机械键盘之前我花了整整一个晚上在京东搜索页里翻来翻去——同一个关键词第1页和第5页的价格能差出一倍热门商品被推到前面但真正性价比高的往往藏在后面的页码里。问题在于一页一页翻可以同时追十几个关键词、几十个商品的价格变化手点就完全不现实了。于是就有了这篇实战的缘起写一个 Python 爬虫输入关键词把京东搜索结果页里的商品名称、价格、店铺、评论数全部抓下来翻页、去重、落库一条龙。文中代码都是我实际跑过的用的是 requests BeautifulSoup SQLAlchemy 这套最经典、最适合入门的组合。不管你是刚学完 Python 基础想拿真实项目练手还是已经在写爬虫但没碰过电商网站这篇文章都能让你直接抄作业同时把请求头、Cookie、翻页参数、中文编码这些爬虫新手必踩的坑一次性讲透。1. 为什么京东搜索页是电商爬虫的黄金入口1.1 搜索结果页的数据密度远超单品详情页很多新手一上来就想去爬商品详情页觉得单个页面信息全。实际做的过程中你会发现详情页要一个一个进每个页面还要等渲染、等接口十几个商品下来请求次数翻了十几倍风控风险也跟着涨。而搜索列表页本身就带着一整批商品的结构化信息商品SKU、标题、价格、店铺、评论数、跳转链接一页30个商品一个请求全部拿到。做一个价格监测或者选品比价的小工具列表页的数据密度已经足够了。从爬虫开发的角度看京东PC端搜索页是服务端渲染的HTML里直接躺着商品卡片不需要等JavaScript动态加载。这一点和很多纯前端渲染的站点差别很大——那些站你拿到手的是个空壳还得上 Selenium 或者找背后的 JSON 接口。京东搜索页省去了这层麻烦对于刚入门的朋友来说是最友好的学习对象。1.2 URL参数拆解keyword、page、psort 各管什么打开浏览器无痕模式访问https://search.jd.com/Search?keywordpython把地址栏里的参数抄下来你会发现核心参数比想象中少。一份常见的搜索URL长这样https://search.jd.com/Search? keywordpython encutf-8 wqpython pvidxxxxxx page1 psort3逐个说下我在实战中确认的作用参数作用取值策略keyword真实搜索词中文必须做URL编码enc页面编码固定 utf-8wq搜索框回显词一般直接复制 keywordpvid一次访问的随机追踪ID不传也能跑省掉page页码核心参数翻页时重点处理见第4章psort排序方式综合、销量、价格等见第4章keyword 传中文时不要自己拼URL交给 requests 的 params 参数自动编码或者用urllib.parse.quote手动编。手动拼字符串最容易出的坑就是忘了编码导致请求返回乱码或者空列表。1.3 页面结构稳定的红利与隐患京东的搜索页结构相对稳定我断断续续写了好几个版本#J_goodsList这个容器ID一直在。这是好事意味着你的解析代码可以长期复用。但也要有心理准备电商平台前端改版是家常便饭某天你突然发现选择器失效了不要慌大概率是结构调整了重新看一眼DOM就能定位。稳定的结构带来的另一个好处是社区里能找到大量现成的选择器写法可以参考。但参考归参考每个爬虫博主写文章的时间点不同京东改过版旧的选择器不一定还灵。你最终还是要学会自己看DOM这个能力才是通用的。2. 请求阶段的三道坎UA、Cookie、超时重试2.1 不带Cookie的第一发请求大概率是空手而归我第一次写京东爬虫时犯过一个低级错误直接拿requests.get()怼搜索URL结果返回的HTML里#J_goodsList是空的页面结构都在商品却一个都没有。排查了很久才发现问题不在解析而在请求本身——京东对完全陌生的请求是会直接不给商品数据的。解决办法很朴素先用同一个requests.Session()去访问一次京东主站https://www.jd.com/把首页的Cookie带回来再拿着这个Session去请求搜索页。Session对象会自动维持Cookie这一步几乎零成本但能解决一大部分返回空列表的问题。import requests HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9, Referer: https://www.jd.com/, } session requests.Session() session.get(https://www.jd.com/, headersHEADERS, timeout10)这里有个经验Referer 最好带上京东很多内部跳转逻辑会校验来源页Referer 填主站地址最保险。另外无痕模式下复制出来的请求头是最干净的别从登录后的浏览器里复制那里带着一堆个人追踪字段反而容易暴露你的抓取行为。2.2 请求头伪装的基本盘很多教程喜欢让你堆一长串请求头什么Accept-Encoding、Connection、sec-ch-ua全给你塞上去。我的实测结论是对于京东搜索页真正起作用的就三样User-Agent、Referer、Accept-Language。User-Agent 必须是一个真实的浏览器UA不要用python-requests这种默认值一眼就会被识别。版本号也不用追求最新但别用一个五年前的老UA有些网站会直接拒绝过旧浏览器的UA。Referer 填https://www.jd.com/是因为我们确实是从主站跳过去的逻辑上自洽。Accept-Language 填中文是为了让京东返回中文页面内容这个字段其实影响不大但写上没坏处。还有个小细节Accept-Encoding不要手动设置成gzip, deflate然后期望 requests 自动解压。让 requests 自己处理压缩就行你手动指定反而可能拿到乱码。2.3 超时、重试与请求节奏设计电商网站请求超时是家常便饭有可能是网络抖动也有可能是风控在观察你。所以请求函数一定要有超时参数和重试机制。我把超时设置成一个元组(5, 15)意思是连接超时5秒读取超时15秒。import time def fetch_html(keyword, page, retries3): url https://search.jd.com/Search params { keyword: keyword, enc: utf-8, wq: keyword, page: page, } for attempt in range(retries): try: resp session.get(url, paramsparams, headersHEADERS, timeout(5, 15)) if resp.status_code 200 and len(resp.text) 1000: return resp.text # 返回了200但内容明显不对说明可能被风控先退避 time.sleep(5 * (attempt 1)) except requests.RequestException as exc: print(f第{attempt 1}次请求失败: {exc}) time.sleep(2 * (attempt 1)) return 重试这里有个原则退避时间必须递增。第一次失败等2秒第二次等4秒第三次等6秒。如果每次都固定等一样的时间遇到风控场景基本等于没用。另外返回200但HTML长度小于1000的情况一定要警惕这说明服务器正常响应了但给的不是商品页可能是验证页或者空壳页面。3. 用 BeautifulSoup 从商品卡片里准确抠出五个字段3.1 商品卡片的DOM结构长什么样分析京东搜索页DOM我建议直接在浏览器里按 F12选中一个商品卡片看它的外层结构。一次实战中我记录的典型结构如下div idJ_goodsList ul classgl-warp li classgl-item>from bs4 import BeautifulSoup def parse_items(html, keyword): soup BeautifulSoup(html, html.parser) lis soup.select(#J_goodsList li.gl-item) results [] for li in lis: sku li.get(data-sku) or em li.select_one(.p-name em) name em.get_text(stripTrue) if em else price_i li.select_one(.p-price i) price price_i.get_text(stripTrue) if price_i else 暂无报价 shop_a li.select_one(.p-shop a) shop shop_a.get_text(stripTrue) if shop_a else 京东自营 cmt_a li.select_one(.p-commit a) comment cmt_a.get_text(stripTrue) if cmt_a else 0条评价 results.append({ sku: sku, keyword: keyword, name: name, price: price, shop: shop, comment: comment, url: fhttps://item.jd.com/{sku}.html if sku else , }) return results选择器为什么用#J_goodsList li.gl-item而不是直接li.gl-item因为页面里可能还有推荐位、广告位它们的结构也是li不加容器限定会混入脏数据。加#J_goodsList前缀等于告诉解析器我只认这个主列表容器里的商品卡片。3.3 图片懒加载和暂无报价这类坑京东搜索页的图片用的是懒加载img标签的src属性在首次加载时是占位图真实图片地址放在>for i in range(1, total_pages 1): page_param i * 2 - 1 html fetch_html(keyword, page_param) rows parse_items(html, keyword) # 处理rows... time.sleep(random.uniform(1, 3))这里给个排查思路如果你发现翻到第2页时返回的商品和第1页完全重复或者页面直接是空的第一件事就是检查 page 是不是传成了偶数。不同时期京东可能调整过这个逻辑网上有的教程说直接递增1有的说奇数递增其实都对因为版本不同。最稳妥的做法是自己在浏览器里点一下第2页看地址栏里 page 到底变成了几。4.2 排序参数怎么确认跟着地址栏走排序参数叫 psort网上能搜到各种版本的参数对照表但我建议你千万别背。原因很简单电商平台改版频繁今天记下来的映射表明天可能就是错的。我在实战里养成了一个习惯——手动打开浏览器搜一个词把综合、销量、评论数、价格升序、价格降序挨个点一遍每次点完都看一眼地址栏 psort 的值记录到自己的笔记里。拿我当时的一份记录举例综合排序地址栏里是 psort3有时候不显示其余排序切换后会变成不同的数字。但这份记录只对我当时抓的那个版本有效所以我不会在这里把数字写死告诉你。你只需要记住方法论浏览器地址栏永远是第一手真值来源任何二手资料都比不上你自己点一遍。这个习惯的价值不只在京东任何网站的排序、筛选参数你都可以用同样的方式确认。爬虫工程师本质上有一半时间在做参数翻译另一半时间在做结构适配前者的基本功就是会看地址栏。4.3 页码上限与数据完整性校验京东搜索页底部有一个翻页控件里面的.p-skip em元素会显示总页数比如共100页。这个数字可以作为循环的终止条件避免你傻乎乎地从1翻到无穷大。def get_total_pages(html): soup BeautifulSoup(html, html.parser) em soup.select_one(.p-skip em) if em: try: return int(em.get_text(stripTrue)) except ValueError: pass return 1但这里有个实战经验京东对部分热门关键词会限制最大可翻页数你拿到手的总页数可能是个虚数翻到后面几页会变成空列表。所以翻页循环里一定要加终止条件——连续两页返回的商品SKU集合完全一样或者连续两页都是空列表就主动停止不要傻等。数据完整性校验也很重要。每页正常是30个商品如果某页解析出来只有10个说明这页可能加载异常或者被风控干扰了这页的数据要么重试要么记录日志后面补抓。别小看这个校验电商页面偶尔会渲染不全不加校验你最后落库的数据就是残缺的分析起来全是坑。5. 数据落库CSV 快速验证与 SQLAlchemy 正式入库5.1 先落 CSV一个编码细节救回你Excel里的中文爬虫写完解析逻辑后我习惯先用CSV验证数据对不对。CSV的好处是零依赖、直接用Excel打开看调试效率极高。但中文落CSV有一个经典坑如果你用encodingutf-8写文件用 Excel 打开会看到一堆乱码因为 Excel 默认按 ANSI 解码。解决办法是写文件时用utf-8-sig编码它会自动在文件头加上BOM标记Excel 就能正确识别了。import csv def save_to_csv(rows, filenamejd_products.csv): with open(filename, a, newline, encodingutf-8-sig) as f: writer csv.DictWriter( f, fieldnames[sku, keyword, name, price, shop, comment, url], ) if f.tell() 0: writer.writeheader() writer.writerows(rows)另一个细节是newline。Windows 下写CSV如果不加这个参数每行之间会多一个空行看起来非常难受。加上之后写出来的文件行间距就正常了。f.tell() 0用来判断文件是否为空为空的时候才写表头这样多次追加数据时不会重复写表头。5.2 SQLAlchemy 模型设计与批量写入数据量一大CSV 就不够用了这时候轮到 SQLAlchemy 出场。它在爬虫里的定位很简单用面向对象的方式操作数据库不用手写 SQL也不用担心不同数据库的方言差距。本地练习用 SQLite真上了服务端可以无缝切到 MySQL。from datetime import datetime from sqlalchemy import create_engine, Column, String, DateTime from sqlalchemy.orm import declarative_base, sessionmaker Base declarative_base() class JdProduct(Base): __tablename__ jd_products sku Column(String(32), primary_keyTrue) keyword Column(String(64), nullableFalse) name Column(String(512)) price Column(String(32)) shop Column(String(128)) comment Column(String(64)) url Column(String(256)) created_at Column(DateTime, defaultdatetime.now) engine create_engine(sqlite:///jd_products.db) Base.metadata.create_all(engine) Session sessionmaker(bindengine)为什么 price 用 String 而不用 Float因为我前面说过京东列表页会有暂无报价这种非数值状态而且价格里可能带货币符号或者千分位。与其在入库时做各种清洗不如先原样存着需要数值分析时再写一个clean_price函数统一转换。这样数据管道每一层只做一件事出问题也容易排查。批量写入时优先用session.add_all()而不是一条条add()提交也只做一次commit()。几十条数据可能感觉不到差别但如果你要抓十个关键词、每个关键词二十页几千条数据入场批量操作的速度优势就非常明显了。5.3 去重与增量更新的简单策略商品SKU是天然的主键去重逻辑就围绕它来做。最简单的方案是抓之前先把库里已有的 SKU 查出来放到一个 set 里解析出一条数据就先判断这个 SKU 在不在 set 里不在才加入待插入列表。session Session() existing_skus {sku for (sku,) in session.query(JdProduct.sku).all()} new_products [] for row in rows: if row[sku] and row[sku] not in existing_skus: new_products.append(JdProduct(**row)) existing_skus.add(row[sku]) if new_products: session.add_all(new_products) session.commit()如果你想做的是价格追踪去重逻辑要反过来——同一个SKU第二次抓到时不跳过而是更新它的价格和评论数。这时候用查一下有就改没有就插的模式for row in rows: if not row[sku]: continue obj session.query(JdProduct).filter_by(skurow[sku]).first() if obj: obj.price row[price] obj.comment row[comment] obj.keyword row[keyword] else: session.add(JdProduct(**row)) session.commit()数据量小的时候这个先查后写够用了。等SKU数量上万再考虑数据库层面的方言特性写法比如 MySQL 的INSERT ... ON DUPLICATE KEY UPDATE或者 PostgreSQL 的ON CONFLICT。爬虫项目最忌一开始就上重型架构先用简单方案跑起来再根据实际瓶颈优化这是我一直推荐的做法。6. 被风控之后怎么办识别、降温与合规边界6.1 空列表、验证页与非正常返回的识别写爬虫一定会遇到风控关键在于能不能第一时间识别出来。京东的风控反馈有几种典型形态第一种是返回200但#J_goodsList里没有任何商品第二种是返回的HTML里出现验证相关标识第三种是内容长度骤减明显不是一个正常搜索页该有的数据量。def check_blocked(html): if len(html) 5000 and gl-item not in html: return True if 验证 in html: return True return False识别到风控后千万不要立刻重试。我踩过这个坑头一次遇到空列表时不服气立刻又发了好几个请求结果后面的请求全部被拦截还把自己网站的IP节奏打乱了。正确做法是退避暂停60秒以上换个关键词再试或者干脆今天就到此为止明天再补抓。爬虫是个长期工程不是一次性的抢钱任务节奏比速度重要得多。6.2 爬虫礼仪限速、频率与数据量控制很多初学者写爬虫时最关心怎么更快我却想劝你先想怎么更慢。对电商网站来说你发请求的节奏越像真人越不容易被针对。我在抓京东时每页之间固定time.sleep(random.uniform(1, 3))随机延迟让请求间隔不那么规律比固定sleep更有用。另外控制单次任务的数据量。我给自己定的规矩是一次任务最多抓三个关键词每个关键词不超过20页跑完就停。数据不够用可以分多次跑但绝不能一口气把几百页全抓完。这种自律不是怕平台而是为了保证数据质量——抓得越快越容易触发风控触发风控后前面抓的数据可能全白费了整体效率反而更低。6.3 合规底线个人学习与官方API之间怎么选最后一定要说清楚合规边界。这篇文章的技术方案定位是个人学习、教学演示、小规模数据研究用途不外乎自己比价、做课程案例、验证爬虫技术。小规模、低频、只爬公开的商品展示信息这是目前社区里比较常见的灰色实践但仍然要遵守平台的 robots 协议和用户协议。如果你的需求是商业化的比如要做竞品价格监测系统、要给客户提供数据服务那就不要自己写爬虫硬刚了。京东官方有开放平台提供搜索、商品、价格、库存等一系列API虽然有些接口需要申请资质但那是正路稳定性和合法性都远胜自建爬虫。我在实际工作中见过太多团队把大量人力投在维护自建爬虫上今天修选择器明天换请求头后天被风控封了一天——回头一算账不如当初花两个星期对接官方API。爬虫能力是很好的技术训练但它不是万能钥匙。知道什么时候该用爬虫什么时候该退回去用正规接口这才是一个合格开发者的判断力。最后分享一个我个人习惯的小技巧写完爬虫后把页面上你能看到的所有关键元素都手动核对一遍——名称有没有截断、价格有没有漏抓、店铺是不是全对应上了。自动化工具最大的风险是出错得很稳定一错就错一整批。抓一页人工看一页确认无误再放全量任务这个习惯帮我避免过无数次返工。京东这类电商站的页面结构再怎么变你的核对流程不变就永远不会被改版打个措手不及。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

ArkTS transform实战指南:从CSS迁移到3D透视动效 2026/9/26 9:02:30

ArkTS transform实战指南:从CSS迁移到3D透视动效

最近在 HarmonyOS 6 上做应用,我把一批原先靠硬改布局数值来实现的动效,全部换成了 ArkTS transform 来做,代码结构干净了很多,效果也直观多了。经常会看到有人在问 ArkTS transform 怎么用,尤其是类似“css 中 rotate…

阅读更多 →
Maya 2022 安装实战:从依赖预检到许可服务避坑全流程 2026/9/26 9:02:23

Maya 2022 安装实战:从依赖预检到许可服务避坑全流程

简介:Maya 2022 是 Autodesk 旗下世界顶级的三维动画设计程序,尤其适合影视广告、角色动画与电影特技等 CG 制作人群。它集建模、动画、模拟、渲染和合成于一体,界面直观、功能齐全,能够帮助用户高效完成电影级视觉效果的生产流程…

阅读更多 →
昇腾Atlas 300V 24G部署YOLO实战:从模型转换到性能调优 2026/9/26 9:02:23

昇腾Atlas 300V 24G部署YOLO实战:从模型转换到性能调优

先说结论:如果你在搜索“atlas部署yolo”和“atlas 300v 24g”,那你大概率是在国产AI推理硬件上跑目标检测模型。这篇文章我会把Atlas 300V 24G这张卡到底是什么、它能干什么、部署YOLO的完整链路,以及我自己实操时踩过的坑一次讲清楚&#x…

阅读更多 →
古诗生成与情感分析实战:从词向量到LSTM的完整链路 2026/9/26 9:02:23

古诗生成与情感分析实战:从词向量到LSTM的完整链路

简介:这份资源是一套以机器学习与自然语言处理为核心的古诗自动生成与情感分析项目,面向具备基础编程能力的自然语言处理学习者、高校学生及竞赛参赛者,覆盖古诗网站语料爬取、数据去重与清洗、分词去停用词、词频统计与关键主题分析、基于格…

阅读更多 →
学生选课系统Java+MySQL课设全攻略:从E-R图到事务避坑 2026/9/26 9:02:23

学生选课系统Java+MySQL课设全攻略:从E-R图到事务避坑

简介:面向数据库课程设计的完整学生选课信息管理系统源码与设计报告,适用于高校计算机相关专业学生完成数据库课程设计、Java 综合实训,也可供初学者参考 MySQL 与桌面应用开发的结合方式。资源采用 C/S 架构,覆盖学生、教师、管理…

阅读更多 →
微软官方.NET Framework修复工具深度解析与实战指南 2026/9/26 9:02:23

微软官方.NET Framework修复工具深度解析与实战指南

1. 这不是“万能补丁”,而是微软亲授的.NET诊断手术刀 你有没有遇到过这样的场景:双击一个企业内部系统安装包,弹出红色错误框——“此应用程序需要 .NET Framework 4.7.2 或更高版本”,而你点开“控制面板→程序和功能→启用或关…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉