Python爬虫实战:Yelp餐厅数据采集完整教程
前言
在数据分析和商业智能领域,餐厅和商户信息的采集是一个常见需求。Yelp作为全球知名的本地商户评论平台,包含了大量有价值的商户信息。本文将详细介绍如何使用Python开发一个高效的Yelp数据爬虫,实现商户信息的批量采集。
技术栈介绍
本项目采用以下技术栈:
- Python 3.x:主要编程语言
- curl_cffi:用于发送HTTP请求,支持浏览器指纹模拟
- 正则表达式:用于数据解析
- JSON处理:解析API响应数据
项目架构设计
核心类:YelpSearchUser
我们设计了一个YelpSearchUser
类来封装所有的爬虫功能,主要包含以下几个核心方法:
__init__()
- 初始化请求头和配置项get()
- 获取搜索结果列表get_detail()
- 获取商户详细信息parse_data()
- 解析搜索结果parse_data_detail()
- 解析详细信息
详细实现分析
1. 初始化配置
def __init__(self):self.headers = {"accept": "*/*","accept-language": "zh-CN,zh;q=0.9","cache-control": "no-cache","pragma": "no-cache","user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
在初始化方法中,我们设置了两套请求头:
headers
:用于API请求html_headers
:用于页面请求
这样做的目的是为了更好地模拟真实浏览器行为,避免被反爬虫机制检测。
2. Cookie处理机制
def cookie_str_to_dict(self, cookie_str: str) -> dict:cookie_dict = {}cookies = [i.strip() for i in cookie_str.split('; ') if i.strip() != ""]for cookie in cookies:key, value = cookie.split('=', 1)cookie_dict[key] = valuereturn cookie_dict
Cookie是维持会话状态的关键,我们实现了Cookie字符串到字典的转换功能,确保请求的连续性。
3. 搜索功能实现
def get(self, page, find_desc, find_loc=""):url = "https://www.yelp.com/search/snippet"if page == 1:params = {"find_desc": find_desc,"find_loc": find_loc,"parent_request_id": "097f2346bb4acfc4","request_origin": "user"}else:start = f"{(page-1)*10}"params = {"find_desc": find_desc,"find_loc": find_loc,"start": start,"parent_request_id": "097f2346bb4acfc4","request_origin": "user"}
搜索功能支持分页,通过start
参数控制结果偏移量,每页显示10条结果。
4. 数据解析核心算法
搜索结果解析
def parse_data(self, data_list):resultList = []for d in data_list:try:bizId = d.get('bizId')if not bizId:continuep_url = "https://www.yelp.com"+d['searchResultBusiness'].get('businessUrl','')item = [bizId, p_url]resultList.append(item)except Exception as e:print("解析错误:", e)return resultList
详细信息解析
def parse_data_datail(self, html, bizId, p_url):html = html.replace(""", '"').replace("/", "/")data_text = "".join(re.findall('<!--\{(.*?)--></script><!-- PRAGMA_YELP_BEGIN_RESPONSE', html))data_text = "{" + data_textdataJson = json.loads(data_text)bs = dataJson[f"Business:{bizId}"]# 提取各种商户信息name = bs.get('name', '')reviewCount = bs.get('reviewCount', 0)rating = bs.get('rating({"roundingMethod":"NEAREST_TENTH"})', '0.0')# ... 更多字段解析
这里使用了正则表达式提取页面中的JSON数据,然后解析出我们需要的商户信息。
数据字段说明
我们提取的商户信息包括:
字段名 | 描述 | 示例 |
---|---|---|
bizId | 商户唯一标识 | "abc123def456" |
name | 商户名称 | "老北京烤鸭店" |
rating | 评分 | "4.5" |
reviewCount | 评论数量 | 128 |
phoneNumber | 电话号码 | "+1-555-123-4567" |
address | 地址 | "123 Main St, New York" |
website_url | 官网链接 | "https://example.com" |
operationHours | 营业时间 | "9:00 AM - 10:00 PM" |
使用示例
if __name__ == '__main__':ysu = YelpSearchUser()# 设置Cookie(从浏览器复制)cookies = 'your_cookie_string_here'# 搜索参数keyword = '' # 搜索关键词,空字符串表示搜索所有location = 'Tokyo' # 搜索地点page = 1 # 页码# 获取搜索结果data = ysu.main(keyword, location, page, cookies, proxies=None)# 获取每个商户的详细信息for url in data['item_list']:result = ysu.main_detail(url, cookies, proxies=None)print(result)
技术亮点
1. 浏览器指纹模拟
使用curl_cffi
库的impersonate="chrome131"
参数,完美模拟Chrome浏览器的TLS指纹和HTTP/2特征。
2. 错误处理机制
while True:try:response = requests.get(url, headers=self.headers, ...)if status_code == 200:return response.json(), status_codeelse:return None, status_codeexcept Exception as e:print("发生错误:", e)
采用无限循环重试机制,确保网络波动不会影响数据采集。
3. 代理支持
代码支持代理服务器配置,可以通过proxies
参数设置代理,提高采集成功率。
注意事项
1. 法律合规
- 遵守Yelp的服务条款
- 控制请求频率,避免对服务器造成压力
- 仅用于学习和研究目的
2. 技术注意点
- Cookie需要定期更新
- 建议添加随机延时避免被检测
- 可以配置用户代理轮换
3. 异常处理
- 网络超时处理
- JSON解析异常处理
- 数据缺失情况处理
总结
本文介绍了一个完整的Yelp数据爬虫实现,涵盖了从搜索到详细信息获取的全流程。通过合理的架构设计和技术选型,实现了高效稳定的数据采集。
这个爬虫项目不仅适用于Yelp,其设计思路和技术方案也可以应用到其他类似的数据采集场景中。希望本文能为大家在爬虫开发方面提供有价值的参考。
相关资源
- curl_cffi官方文档
- Python正则表达式教程
- HTTP请求头详解
本文仅供学习交流使用,请遵守相关法律法规和网站服务条款。