简介:这是一份面向 Python 爬虫开发者与电商数据分析师的轻量级爬虫库 Shopee Crawler,版本 0.1.2。它基于 Shopee 平台商品抓取场景,封装了爬虫主逻辑、工具函数与模块初始化配置,可用于商品列表、详情、关键词等数据的定向采集,也可作为电商爬虫框架的参考样例。资源包共包含 16 个文件,以 Python 源码为核心(8 个 .py 文件),配合 4 个文本说明、2 个包元数据文件、1 个 Markdown 文档和 1 个配置文件,整体体积仅 4KB,结构非常精简。核心源码覆盖爬虫入口、抓取流程及辅助工具,配置文件与包元数据便于安装分发,文档可帮助快速上手。目前已有 609 人学习下载,适合希望快速掌握电商爬虫实现、或需要参考轻量级爬虫封装思路的初中级 Python 开发者,拿到后可直接阅读源码、二次修改并应用于自身数据采集项目。
1. 用 shopee_crawler 0.1.2 之前,先知道它解决什么问题
做电商数据分析、竞品比价或者选品调研时,Shopee 平台上的商品标题、价格、销量、评价散落在页面各处,手工复制撑不过几十条。shopee_crawler 就是为这个场景准备的一组 Python 工具库,0.1.2 版本以 tar.gz 源码包形式分发,安装后提供搜索、详情、评价等采集入口。这篇会从解压安装开始,走到请求封装与参数解析,最后给出一套限速、重试和断点续爬的稳定性方案。适合刚接触爬虫的 Python 开发者,也适合需要把采集任务长期跑下去的工程师。重点不是直接拿到现成数据,而是理解这个库在请求、解析、容错上替我们做了什么。
2. 把 shopee_crawler-0.1.2.tar.gz 解压装进 Python 环境
2.1 从下载目录到 site-packages:tar.gz 的三种安装路径
Linux 下最常见的安装报错是路径打错,终端直接提示tar.gz没有那个文件或目录。shell 里逐字敲版本号时,0.1.2 很容易被看成 0.1.20,或者 cd 进了解压目录但文件名不匹配。我一般先执行ls -l shopee_crawler*确认实际文件名,再决定用哪种方式安装。
# 方式一:先解压再手动安装 tar -xzf shopee_crawler-0.1.2.tar.gz cd shopee_crawler-0.1.2 python setup.py install # 方式二:跳过手动解压,pip 直接消费压缩包 pip install ./shopee_crawler-0.1.2.tar.gz # 方式三:解压后以可编辑模式安装,便于边读源码边改 pip install -e ./shopee_crawler-0.1.2三种方式的差别在可维护性。方式一是老派做法,适合想在 setup.py 里确认依赖清单的环境;方式二最省事,pip 会先解压再执行构建,日常使用首选;方式三的-e表示 editable 模式,源码改动立即生效,适合要二次开发这个库的人。无论选哪种,装完都要验证包是否真正进入当前环境。
python -c "import shopee_crawler; print(shopee_crawler.__version__)"输出 0.1.2 才算成功。这里有个高频坑:如果 shell 还停留在解压出来的源码目录,import优先命中当前目录,测的是源码而不是已安装的包,建议切到 /tmp 或任意空目录再验证。Python 版本方面,0.1.2 这类早期库通常要求 3.7 以上,建了虚拟环境就必须先激活再装,否则包落进系统环境,依赖隔离形同虚设。对照常见 python 安装教程里的习惯,爬虫项目最好单独建 venv,不要和开发机上的其他项目共用解释器。
2.2 setup.py 里藏着的依赖与元信息
解压后先别急着执行安装,打开shopee_crawler-0.1.2/setup.py看 install_requires 列表。这个列表直接决定运行环境还缺哪些包。CPU 密集的解析任务常用 lxml,轻量抓取用 requests,某些反爬场景可能还需要 curl_cffi 一类能模拟浏览器指纹的请求库。
# setup.py 常见结构(以实际包为准) from setuptools import setup, find_packages setup( name="shopee_crawler", version="0.1.2", packages=find_packages(where="src"), install_requires=[ "requests>=2.28", "beautifulsoup4>=4.11", "lxml>=4.9", ], python_requires=">=3.7", )packages=find_packages(where="src")表示源码采用 src 目录布局,安装时会把 src 下的包复制到 site-packages。install_requires 里的版本下限是硬约束:系统已有 requests 2.20 时,pip 会自动升级到满足条件的版本;如果某些包和公司内部源冲突,安装就会停下来报错。依赖与用途对应关系可以按下面这张表排查。
| 依赖包 | 用途 | 缺失时的典型报错 |
|---|---|---|
| requests | 发起 HTTP 请求 | ModuleNotFoundError: requests |
| beautifulsoup4 | 解析 HTML 页面片段 | No module named bs4 |
| lxml | 加速 HTML/XML 解析 | ImportError: lxml not found |
看明白这一步,后面遇到 ImportError 就知道先去查依赖版本,而不是反复重装主包。0.1.2 是早期版本,依赖写得往往偏保守,项目里已有更高版本时通常可以直接复用,不用降级。
2.3 目录结构:请求、解析、工具三层各管一段
进入 src 目录后,通常会看到 crawlers、parsers、utils 三个子目录。crawlers 负责发请求,parsers 负责从 HTML 或 JSON 里抽字段,utils 负责写文件、格式化时间这类杂活。理解这个分层对后续调参很重要:改请求头在 crawlers 里,改字段提取在 parsers 里,改输出路径在 utils 里,不要拿着文件全局搜。
我习惯先跑一次python -m shopee_crawler --help看有没有 CLI 入口。0.x 版本很多库只提供 Python API,没有命令行工具,这时就去 README 找示例代码。0.1.2 这个版本号意味着接口可能还在变化,示例里的函数签名务必以实际安装包为准,遇到TypeError: unexpected keyword argument时就去查源码签名,不是示例写错,是版本已经动了。
提示:pip 安装后找不到包,优先执行
pip show shopee_crawler看 Location 字段,确认它落在当前虚拟环境的 site-packages 里。
3. shopee_crawler 的请求封装与商品 URL 参数解析
3.1 为什么直接请求 HTML 不如调 API 端点稳定
在浏览器里翻 Shopee 商品页,拿到的是渲染后的 HTML,里面夹着大量脚本、样式和埋点字段,解析成本高,页面一改版就全挂。处理这类电商平台时,我优先找页面背后真正返回数据的接口,通常是 JSON:字段稳定、体积小、层级路径可预测。shopee_crawler 的设计思路也在这个方向,它把 URL 拼装逻辑收敛到 crawlers 模块,对外暴露参数化方法。
from shopee_crawler.crawlers import SearchCrawler crawler = SearchCrawler() items = crawler.search(keyword="wireless earphone", limit=50)这句调用背后至少做了三件事:拼接带查询参数的 URL、携带浏览器特征的请求头、把返回内容按统一结构交还给调用方。所以用这个库时,不要绕过封装自己用 requests.get,直接调方法才能享受到超时、重试这些内置行为。同步 for 循环适合先把链路跑通,采集量上去之后再考虑协程或者多进程分片,那是另一层优化。
3.2 关键请求参数:keyword、limit、page 与 shopid
search 方法内部会构造类似下面的请求,参数名是常见实现,具体以库源码为准。理解每个字段的含义,调参才有的放矢,不至于对着翻页数据发愣。
params = { "keyword": keyword, "limit": limit, "page": page, "sort": sort, "by": "relevancy", } headers = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "referer": "https://shopee.sg/", } response = requests.get( "https://shopee.sg/api/v4/search/search_items", params=params, headers=headers, timeout=10, )参数说明集中在下面这张表,方便对照修改。
| 参数 | 常见取值 | 作用 |
|---|---|---|
| keyword | 字符串,URL 自动编码 | 搜索关键词,核心过滤条件 |
| limit | 10 / 20 / 50 | 单页返回条数,过大可能被拒绝 |
| page | 从 0 开始的整数 | 分页游标,配合 limit 翻页 |
| sort | relevancy / sales / price | 排序方式,运营看爆款常用 sales |
| by | relevancy / ctime | 配合 sort 使用的排序依据 |
limit 和 page 必须成对出现,每翻一页 page 加 1,limit 保持不变。新手只调 limit 不调 page,就会反复拿到第一页的重复数据,看起来像是抓取 bug,其实是分页参数没接上。网络请求要带 timeout,10 秒是合理起步值;被限流时响应变慢,提到 15 秒可以,但不建议超过 30,否则单个慢请求会拖垮整轮采集的节奏。
注意:limit 设为 100 不代表一定返回 100 条,服务端有最大上限,超限时以实际返回条数为准。
3.3 解析层为什么比正则稳
商品列表 JSON 的字段层级比较深,例如data.items[i].item_basic.name存商品名,price 字段通常按分存储而不是元。shopee_crawler 的 parsers 模块把这些路径封装成方法,外部拿到的已经是整理好的 dict,业务代码里就不用到处写["data"]["items"][0]这种脆弱索引。
from shopee_crawler.parsers import parse_search_items raw = crawler.search("smart watch", limit=20) parsed = parse_search_items(raw) print(parsed[0]["name"], parsed[0]["price"])如果解析层输出 dataclass,字段会带类型提示,写起来更安心。遇到解析结果为空,先检查原始返回是不是登录墙或验证码页面,这一步用库内置的 response 文本日志确认,比在 UI 上瞎猜有效得多。另外要注意,解析层不负责重试,网络层的重试在 crawlers 里配置,两块逻辑别混在一起,否则排错时无从下手。
4. 用 shopee_crawler 抓商品搜索与详情的最小可行代码
4.1 搭一个能跑通的主流程
前两章把安装和原理讲完,这里给一个能直接落盘的最小脚本。假定已按第二章装好包,把下面代码保存为run_demo.py,在虚拟环境里执行。
import json from shopee_crawler.crawlers import SearchCrawler, DetailCrawler from shopee_crawler.parsers import parse_search_items, parse_detail def main(): # 搜索阶段:抓前 3 页,每页 20 条 search = SearchCrawler() all_items = [] for page in range(3): raw = search.search("phone grip", limit=20, page=page) all_items.extend(parse_search_items(raw)) # 详情阶段:取前 5 个商品抓详情 detail = DetailCrawler() details = [] for item in all_items[:5]: d = detail.get(item["shopid"], item["itemid"]) details.append(parse_detail(d)) with open("output.json", "w", encoding="utf-8") as f: json.dump({"search_count": len(all_items), "details": details}, f, ensure_ascii=False, indent=2) print(f"done: {len(all_items)} search items, {len(details)} details") if __name__ == "__main__": main()代码里SearchCrawler.search返回原始响应,parse_search_items把商品列表解析成结构化数据,可以安全地取item["shopid"]和item["itemid"]。detail 方法用这两个 ID 作为商品唯一标识,这是电商数据去重的关键。page 从 0 到 2 是为了演示多页抓取,真实任务里翻页深度建议用配置文件控制,不要写死在脚本里。同步循环在这里是有意的:先确认每一步的结果,再考虑并发,避免一上来就把请求频率拉满。
4.2 商品详情与评价的字段取舍
详情接口的字段远多于搜索列表,完整标题、分类路径、库存、销量、历史价格、店铺信息都有。如果全量落盘,一天跑几万条就会膨胀出大量无用字段,后续清洗反而更费时间。我一般只挑关键字段,按分析目标裁剪,下面是一份可直接用的切片。
detail_slice = { "itemid": d["itemid"], "name": d["name"], "price": d["price"], "historical_sold": d["historical_sold"], "stock": d["stock"], "rating_star": d["rating_star"], "categories": d.get("categories", []), }price 从分转成元就在这一步处理,保留两位小数;categories 用get加默认空列表,避免个别商品缺字段时抛 KeyError。评价数据一般走独立接口,字段包括评分、评价文本、图片、追评内容,文本适合做情感分析,评分适合做质量统计。这两类建议分文件落盘,不要混进商品主表,评价是随时间增长的数据,和商品快照的更新频率完全不一样。
4.3 落盘格式:JSON 还是 CSV
商品详情是嵌套结构,categories 是列表,存 CSV 要么拍平、要么用分隔符拼,都很别扭。我的原则是:原始全量数据用 JSON 存档,用于二次分析;字段少、结构平的评价数据用 CSV,方便 Excel 直接打开。两类文件用同一时间前缀命名,按采集轮次对齐。
python run_demo.py ls -lh *.json *.csv跑完先看输出文件大小。search_count 远小于预期,优先检查网络是否稳定;details 为空,多半是 shopid 和 itemid 的类型不对,回第三章节把参数类型对齐。示例里的 print 只是演示,正式任务建议换 logging 模块,把每轮抓取时间、条数、失败数量记录下来,后面调限速参数时这些日志就是判断依据。CSV 落盘记得指定encoding="utf-8-sig",否则数据里有中文时,Windows 上的 Excel 打开会乱码。
5. shopee_crawler 的稳定性控制:限速、重试与断点续爬
5.1 用一个任务类把限速做进去
爬虫跑到第 2000 条时被限流,比解析报错更难排查。shopee_crawler 的封装不会帮你做等待,这部分逻辑必须放在业务层。常见做法是循环里按随机间隔休眠,固定间隔容易被识别成脚本行为。
import time, random for page in range(10): raw = search.search("phone grip", limit=20, page=page) time.sleep(random.uniform(2.0, 5.0))随机区间的上限不要拉太大,1 到 30 秒的跨度会让整个任务慢到无法接受。配合重试机制:返回内容为空或状态码不是 200 时,暂停 60 秒再重试,连续失败 3 次就放弃当前页,记录到失败清单。
5.2 断点续爬的落盘策略
整批任务中断后从零开始抓,既浪费配额又浪费时间。断点续爬的核心是记录已完成页码或 itemid,启动时跳过已处理的部分,状态记录方式如下。
| 记录内容 | 作用 | 更新时机 |
|---|---|---|
| page 游标 | 重入搜索循环 | 每页成功后 |
| itemid 集合 | 跳过已抓详情 | 每次详情落盘后 |
| 时间戳 | 评估采集耗时 | 每批结束后 |
已完成的 itemid 写进done.txt,每行一个 ID,启动脚本时读成 set,详情请求前先判断 ID 是否在集合中。任务中断后重跑,只会补抓缺失部分,日志里同时输出新抓和跳过的数量,一眼确认断点是否生效。实际调限速参数时,从 sleep(2) 起步,观察返回码分布,没有出现 429 或 403 再逐步收紧到 1.5 秒,这是最稳的节奏。
本文还有配套的精品资源,点击获取