import requests
import json
from urllib.parse import urlencode
import time
class TmallCrawler:
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': 'https://list.tmall.com/'
}
self.session = requests.Session()
def get_list_data(self, keyword, page=1, pagesize=60):
"""获取商品列表数据"""
base_url = "https://list.tmall.com/search_product.htm"
# 构建查询参数
params = {
'q': keyword,
'type': 'p',
'spm': 'a220m.1000858.1000724',
'style': 'g',
'from': 'mallfp..pc_1_searchbutton',
's': (page - 1) * pagesize # 计算起始位置
}
url = f"{base_url}?{urlencode(params)}"
try:
response = self.session.get(url, headers=self.headers, timeout=10)
response.raise_for_status()
# 天猫列表页数据通常通过JavaScript加载
# 这里需要解析页面中的JSON数据
return self._parse_page_data(response.text)
except requests.RequestException as e:
print(f"请求失败: {e}")
return None
def _parse_page_data(self, html):
"""解析页面中的商品数据"""
import re
# 查找JSON数据(天猫通常将数据放在JS变量中)
pattern = r'g_page_config\s*=\s*({.*?});'
match = re.search(pattern, html, re.DOTALL)
if match:
try:
data = json.loads(match.group(1))
items = data.get('mods', {}).get('itemlist', {}).get('data', {}).get('auctions', [])
product_list = []
for item in items:
product = {
'title': item.get('title', ''),
'price': item.get('view_price', ''),
'sales': item.get('view_sales', ''),
'shop': item.get('nick', ''),
'item_id': item.get('nid', ''),
'detail_url': item.get('detail_url', '')
}
product_list.append(product)
return product_list
except json.JSONDecodeError:
print("JSON解析失败")
return []
return []
def crawl_pages(self, keyword, max_pages=5):
"""爬取多页数据"""
all_products = []
for page in range(1, max_pages + 1):
print(f"正在爬取第 {page} 页...")
products = self.get_list_data(keyword, page=page)
if products:
all_products.extend(products)
print(f"第 {page} 页获取到 {len(products)} 个商品")
# 添加延迟,避免请求过快
time.sleep(2)
return all_products
# 使用示例
if __name__ == "__main__":
crawler = TmallCrawler()
# 搜索关键词
keyword = "手机"
# 爬取前3页数据
products = crawler.crawl_pages(keyword, max_pages=3)
# 打印结果
print(f"\n总共获取到 {len(products)} 个商品:")
for i, product in enumerate(products[:5], 1): # 只显示前5个
print(f"{i}. {product['title'][:50]}... | 价格: {product['price']} | 销量: {product['sales']}")
# 保存到JSON文件
with open('tmall_products.json', 'w', encoding='utf-8') as f:
json.dump(products, f, ensure_ascii=False, indent=2)
print("\n数据已保存到 tmall_products.json")
核心要点:
- 请求头设置:必须包含User-Agent和Referer,否则会被拦截
- 参数构造:天猫搜索页通过URL参数控制分页,
s参数是起始位置
- 数据解析:商品数据藏在
g_page_config这个JS变量里,用正则提取JSON
- 反爬处理:添加
time.sleep()避免请求过快被ban
需要注意:
- 天猫有反爬机制,可能需要处理cookies或验证码
- 数据是动态加载的,如果页面改版需要调整解析逻辑
- 考虑使用代理IP应对频繁访问
一句话建议: 重点搞定页面数据解析,天猫的数据藏在JS变量里。