01|故事開局:當(dāng)手動(dòng)復(fù)制遇到“滑不到底”的頁(yè)面
2025 年 3 月,杭州濱江。
運(yùn)營(yíng)妹子阿 May 把 MacBook 轉(zhuǎn)過來:“這家金冠微店每天上新 50 款,價(jià)格一天三變,我滑到 300 條就閃退,再滑手就要廢了?!?br>我瞄了眼地址欄——
https://weidian.com/?userid=123456789
經(jīng)典的“店鋪首頁(yè) + 動(dòng)態(tài)加載”套路。
于是,我打開 VS Code,敲下第一行 import requests。
那一刻,檸檬芋圓的味道,已經(jīng)在我嘴里爆漿。
02|技術(shù)選型:為什么放棄 Selenium,只用 Requests+BeautifulSoup?
方案 | 速度 | 反爬難度 | 結(jié)論 |
---|---|---|---|
Selenium | 慢 | 低 | 適合 demo,不適合夜宵 |
Requests+BS4 | 快 | 中 | 夠輕、夠快、夠穩(wěn) |
Pyppeteer | 快 | 高 | 殺雞焉用牛刀 微店 PC 端列表頁(yè)其實(shí)偷偷留了一個(gè)靜態(tài) HTML 兜底,只要帶對(duì) Cookie,就能直接拿到商品塊,無需瀏覽器渲染。 于是,我拍了拍阿 May 的肩膀: “檸檬芋圓等會(huì)兒再點(diǎn),我先給你跑 1 800 條數(shù)據(jù),3 分鐘見?!?/td> |
03|30 行核心代碼:讓微店“裸奔”
Python
import requests, csv, time, random
from bs4 import BeautifulSoup
from urllib.parse import urljoin
SHOP_ID = '123456789' # ① 目標(biāo)店鋪 ID
COOKIES = {'wdtoken': '抓包所得'} # ② 登錄后 F12 抄
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'Referer': f'https://weidian.com/?userid={SHOP_ID}'
}
def crawl_page(page=1):
"""拉取一頁(yè) 48 件商品"""
url = f'https://weidian.com/user/{SHOP_ID}/items'
params = {'p': page, 'type': 1}
res = requests.get(url, headers=HEADERS, cookies=COOKIES, params=params, timeout=10)
res.raise_for_status()
return res.text
def parse(html):
"""解析出商品 4 件套"""
soup = BeautifulSoup(html, 'lxml')
for div in soup.select('.item-root'):
yield {
'title': div.select_one('.item-title').text.strip(),
'price': div.select_one('.item-price').text.strip(),
'sales': div.select_one('.item-sales').text.strip(), # 已售 x 件
'link' : urljoin('https://weidian.com', div.a['href']),
}
def main():
with open('weidian.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = None
for p in range(1, 40): # ③ 保守翻 40 頁(yè)
print(f'[+] 正在偷看第 {p} 頁(yè)')
html = crawl_page(p)
for prod in parse(html):
if writer is None:
writer = csv.DictWriter(f, fieldnames=prod.keys())
writer.writeheader()
writer.writerow(prod)
time.sleep(random.uniform(1, 2)) # ④ 紳士限速
if __name__ == '__main__':
main()
代碼跑起來的樣子:
https://miro.medium.com/max/640/1*0Z8Z7dXa3Y5fFcXkPwXJkA.gif
(GIF 僅示意,非真實(shí)截圖)
3 分鐘后,同目錄下多出一個(gè) 1 800 行的 weidian.csv:
title | price | sales | link |
---|---|---|---|
韓國(guó)東大門同款毛絨漁夫帽 | ¥39.9 | 已售 2.3k | https://weidian.com/item.html?itemID=xxx 阿 May 直接 Excel 透視表,把價(jià)格段、銷量分布、上新節(jié)奏一次性拉了出來。 她抬頭看我,眼神像發(fā)現(xiàn)新大陸: “原來技術(shù)可以這么性感?” |
04|進(jìn)階:把詳情頁(yè)“掏空”,再薅 5 個(gè)字段
列表頁(yè)只能望梅止渴,真正的戰(zhàn)場(chǎng)在詳情頁(yè):
- 主圖 9 張
- SKU 庫(kù)存
- 圖文詳情 HTML
- 上架時(shí)間
- 運(yùn)費(fèi)模板
- 微店詳情頁(yè)接口同樣留了靜態(tài)口子:
GET https://weidian.com/item.html?itemID=xxxx
只要帶對(duì) Cookie,返回就是完整 HTML,圖片懶加載鏈接直接躺在 img data-original 里。 - 我順手寫了一個(gè)“詳情頁(yè)補(bǔ)全函數(shù)”:
Python
def detail(url):
html = requests.get(url, headers=HEADERS, cookies=COOKIES, timeout=10).text
s = BeautifulSoup(html, 'lxml')
return {
'images': [img['data-original'] for img in s.select('.slider-item img')],
'desc' : s.select_one('.detail-txt').text.strip()[:200], # 前 200 字描述
'sku' : [i.text for i in s.select('.sku-name')],
'postage': s.select_one('.postage-txt').text.strip(),
'added' : s.select_one('.added-time').text.strip() # 上架時(shí)間
}
在 main() 里每寫完一行列表,就同步去拉詳情,數(shù)據(jù)維度瞬間從 4 列擴(kuò)到 10+ 列。
阿 May 把文件拖到 Power BI,拖拽出一張“上架時(shí)間-銷量”象限圖,指著右上角 quadrant 說:
“這些就是潛力爆款,明天讓采購(gòu)去談供應(yīng)鏈!”
05|反爬錦囊:讓蜘蛛學(xué)會(huì)“紳士步”
微店反爬三板斧:
- 同一 IP 連續(xù) 200 次請(qǐng)求 → 彈 403
- 請(qǐng)求缺 Referer / Cookie → 重定向登錄
- 流量異常 → 滑塊驗(yàn)證碼
- 我的對(duì)策:
- 免費(fèi)代理池 https://github.com/fate0/proxylist + requests 的 proxies 參數(shù)
- 每 50 頁(yè)換一次 UA,Referer 全程帶店鋪首頁(yè)
- 隨機(jī) sleep 1~2 s,偶爾“人性化”停 5 s
- 把 Cookie 的 wdtoken 做成環(huán)境變量,30 分鐘熱更新一次
- 跑了一周,IP 沒被封,數(shù)據(jù)每天增量 200+ 條, Lemon Yakult 也如約到賬 10 杯。
06|數(shù)據(jù)落地:MySQL+Redis,讓報(bào)表自動(dòng)“長(zhǎng)”出來
CSV 只是前菜,真正的儀式感是自動(dòng)化數(shù)據(jù)倉(cāng)庫(kù):
- 爬蟲 → MySQL 替換插入(唯一索引 itemID)
- 每日增量 → Redis 隊(duì)列 推給 BI 服務(wù)
- 凌晨 3 點(diǎn) Airflow 調(diào)度 → 自動(dòng)刷寬表 → 企業(yè)微信推送“昨日競(jìng)品上新 47 款,漲價(jià) 12 款”
- 阿 May 再也不用熬夜,她現(xiàn)在在健身房練馬甲線,偶爾給我發(fā)微信:
“報(bào)表已閱,今天繼續(xù)躺贏?!?/li>
07|法律與道德:先問能不能爬,再問怎么爬
- 只爬公開頁(yè)面數(shù)據(jù),不碰用戶隱私、訂單接口
- 遵循 robots.txt(微店目前未禁止 user-agent: *)
- 合理限速,單 IP QPS < 1
- 數(shù)據(jù)僅內(nèi)部競(jìng)品分析,不商用外泄、不二次販賣
- 技術(shù)是把刀,握刀的人決定它是廚具還是兇器。
愿我們都做溫柔的數(shù)字礦工,而不是粗暴的數(shù)據(jù)海盜。
08|尾聲:當(dāng)檸檬芋圓變成美金,代碼就有了溫度
一個(gè)月后,阿 May 團(tuán)隊(duì)靠這份“競(jìng)品數(shù)據(jù)庫(kù)”:
- 提前 7 天預(yù)判漲價(jià),鎖貨 3 000 件
- 找到 2 家低 8% 價(jià)格的同源工廠
- 單款毛利 +22%,凈利潤(rùn) 6.3 萬人民幣
- 她給我發(fā)了一個(gè) 66.66 的紅包,備注:
“檸檬芋圓可以融化,數(shù)據(jù)不會(huì)。
愿我們都能用技術(shù),讓熬夜的人早點(diǎn)回家?!?/li>
(完)
附錄:一鍵運(yùn)行環(huán)境
bash
# 1. 克隆示例倉(cāng)庫(kù)(含完整代碼)
git clone https://github.com/yourname/weidian-spider-demo.git
cd weidian-spider-demo
# 2. 安裝依賴
pip install requests beautifulsoup4 lxml pandas
# 3. 填入 Cookie & ShopID
vim config.py
# 4. 啟動(dòng)
python spider.py
祝爬得開心,喝得自由。