使用BeautifulSoup抓取含::before伪元素网页数据的解决方法
问题说明
你抓不到内容和::before伪元素没有任何关系。CSS伪元素是浏览器渲染页面时根据CSS规则动态生成的,不会存在于requests获取到的原始HTML源码中,BeautifulSoup解析时完全接触不到这部分内容,不可能是它导致抓取失败。
你现在爬取失败的核心原因是:目标站点是前端框架渲染的单页应用,requests.get拿到的初始响应里,<div id="app">只是一个空的容器节点,所有产品数据都是页面在浏览器中加载完成后,通过JS异步调用后端接口拉取数据,再动态渲染到页面上的。你直接解析初始的空HTML,自然找不到产品标题和对应链接。
除此之外你现有代码还有几个明显的逻辑错误:
- 没有配置请求头,直接发起裸请求很容易被站点反爬策略拦截,返回空白页或者验证页
- 节点查找逻辑错误:
soup.find('div', {'id':'app'})拿到的是整个页面的根容器单个节点,直接循环遍历只能拿到节点内部的零散文本节点,根本抓不到嵌套的产品卡片 - 缩进错误:写入Excel的逻辑被放在了产品遍历循环的外部,最终只会保存最后一个抓到的产品数据,前面抓到的内容都会被覆盖
可选解决方法
优先选第一种方案,效率最高也最稳定:
- 接口直爬方案:打开目标站点按F12调出开发者工具,切换到「网络」面板,刷新页面后筛选Fetch/XHR类型的请求,就能找到页面加载产品列表时调用的后端接口。接口直接返回结构化的JSON数据,里面已经包含了所有产品的标题、跳转链接、价格等信息,不需要解析HTML,请求的时候带上正常浏览器的请求头就能直接拿到数据,速度比渲染页面快数倍。
- JS渲染方案:如果不想分析接口,可以替换成支持JS渲染的爬虫库,比如
playwright、selenium、requests-html,模拟浏览器打开页面,等所有产品内容都渲染完成后,再提取DOM节点内容即可,这种方案写起来更简单,但运行速度更慢,对资源占用更高。
参考修正逻辑
如果使用JS渲染拿到完整HTML后,解析DOM的逻辑需要做如下修正:
# 注意用find_all查找所有产品卡片节点,不要直接找id=app的根节点循环 productlist = soup.find_all('div', {'class':'ptile-v2'}) # 产品卡片的class可以在渲染完成后的DOM里确认 for productinfo in productlist: # 直接调用get_text方法拿文本,不需要额外封装函数 productnaam = productinfo.find('h3', {'class':'card-title lvl3'}).get_text(strip=True) # 直接取href属性拿链接 product_url = productinfo.find('a' , {'class':'ptile-v2_link'}).get('href') # 写入逻辑要放在循环内部,每个产品存一行 sheet.append([productnaam, product_url]) print(productnaam, product_url)
提示:不管用哪种方案,都记得给请求加上和浏览器一致的User-Agent头,不要用默认的requests请求标识,否则很容易被反爬拦截。
内容的提问来源于stack exchange,提问作者Rick Prins
相关产品推荐
相关产品推荐

