爬取vivo官网手机仅获取热门机型,如何实现全型号数据爬取
问题原因
你当前代码只能爬取热门机型的核心原因是:该页面除首屏默认展示的热门机型外,其余分系列机型为动态加载内容,初始requests.get拿到的静态HTML中仅包含热门机型的DOM节点,其余机型节点需要前端触发对应系列标签的点击事件后,才会通过接口异步加载插入页面,因此直接解析首屏HTML无法拿到全量机型链接。
调整思路
- 不需要引入Selenium等自动化渲染工具,直接调用页面加载机型列表的后端接口即可拿到全量数据
- 先从首屏HTML中提取所有机型系列的ID,再逐个请求对应系列的机型列表接口,解析拿到所有机型的详情页链接
- 补充请求头模拟浏览器访问,避免被站点反爬拦截
- 增加异常捕获,避免单个机型页面结构异常导致整个爬取任务中断
- 修正原代码中错误的输出文件名(原代码写的是oppophones.csv,实际为vivo机型数据)
调整后可运行代码
import pandas as pd from bs4 import BeautifulSoup import requests import time # 统一请求头,模拟浏览器访问 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", "Referer": "https://www.vivo.com/in/support/system-update" } baseurl = 'https://www.vivo.com' def get_all_phone_links(): all_links = [] # 先拿首屏内容,获取所有机型系列ID r = requests.get('https://www.vivo.com/in/support/system-update', headers=headers) sp = BeautifulSoup(r.text, 'lxml') # 先提取首屏已加载的热门机型链接 hot_links = sp.select('li.box-model-item a') all_links.extend([baseurl + link.attrs['href'] for link in hot_links]) # 提取所有非热门系列的ID series_items = sp.select('.series-item[data-id]') series_ids = [item['data-id'] for item in series_items if item['data-id'] != '0'] # 0对应热门机型,已经抓取过 # 逐个系列请求接口拿机型列表 list_api = 'https://www.vivo.com/in/support/systemUpdate/getPhoneList' for sid in series_ids: resp = requests.post(list_api, data={"seriesId": sid}, headers=headers) if resp.status_code != 200: continue # 接口返回对应系列的HTML片段,直接解析即可 series_sp = BeautifulSoup(resp.text, 'lxml') series_links = series_sp.select('li.box-model-item a') all_links.extend([baseurl + link.attrs['href'] for link in series_links]) time.sleep(0.5) # 增加短延时,避免请求过于频繁被拦截 # 链接去重 return list(set(all_links)) def phone_data(url): try: r = requests.get(url, headers=headers, timeout=10) sp = BeautifulSoup(r.text, 'lxml') release_date_tag = sp.select_one('.no-flip-over:-soup-contains("Release date") + span') downloads_tag = sp.select_one('.no-flip-over:-soup-contains("Downloads") + span') data = { "phone_url": url, "Release_Date": release_date_tag.text.strip() if release_date_tag else "", "Downloads": downloads_tag.text.strip() if downloads_tag else "", } return data except Exception as e: print(f"爬取{url}失败: {str(e)}") return None def main(): urls = get_all_phone_links() results = [] for url in urls: res = phone_data(url) if res: results.append(res) time.sleep(0.3) return results if __name__ == "__main__": df = pd.DataFrame(main()) df.to_csv("vivo_phones.csv", index=False) print(f"爬取完成,共保存{len(df)}条机型数据,已写入vivo_phones.csv")
注意事项
- 代码中设置的延时不要随意调小,避免给站点服务器造成过大压力,也防止自身IP被临时封禁
- 如果后续站点调整了接口路径或者HTML类名,对应更新选择器或者接口地址即可
- 爬取到的数据请仅用于个人学习用途,遵守站点相关规则
内容的提问来源于stack exchange,提问作者Prathik Thamalla
相关产品推荐
相关产品推荐

