XPath+lxml爬取Trustpilot评论有用性分数无输出,请求技术支持
解决Trustpilot评论有用性分数爬取问题
问题根源
你当前依赖的XPath使用了动态生成的类名(比如styles_usefulLabel__qz3JV),这类由前端框架自动生成的class名会随网站更新频繁变化,这就是之前能爬取成功、现在失效的核心原因。
解决方案
改用基于元素结构和稳定属性的XPath定位,同时遍历每条评论的独立容器,确保评论内容与有用性分数一一对应,覆盖0票的场景:
修改后的代码
#%% Step 1: Import all of the extensions and packages. from lxml import html import glob import pandas as pd import re reviewcontent = [] helpfulness_scores = [] # 初始化分数列表,修正原代码变量未定义问题 #%% path = pathx # 确保pathx是你本地HTML文件的实际路径 for files in glob.glob(path + "*.htm*"): with open(files, "r", encoding="utf-8", errors="ignore") as f: page = f.read() tree = html.fromstring(page) # 定位每条评论的根容器(依赖稳定的data-review-id属性) review_containers = tree.xpath('//div[@data-review-id]') for container in review_containers: # 提取评论内容 review_nodes = container.xpath('.//div[contains(@class, "styles_reviewContent")]/text()') review_text = ' '.join([r.strip() for r in review_nodes if r.strip()]) reviewcontent.append(review_text) # 提取有用性分数 useful_label = container.xpath('.//span[contains(@class, "styles_usefulLabel")]/text()') if useful_label: label_text = useful_label[0].strip() # 从文本中提取数字,比如"Useful (2)"取2,纯"Useful"视为0票 score_match = re.search(r'\d+', label_text) helpfulness_scores.append(int(score_match.group()) if score_match else 0) else: # 未找到有用性标签,说明是0票 helpfulness_scores.append(0) # 转为DataFrame方便后续处理 df = pd.DataFrame({ 'review_content': reviewcontent, 'usefulness_score': helpfulness_scores }) print(df.head())
关键调整说明
- 稳定容器定位:用
//div[@data-review-id]定位每条评论的根节点,这个属性是Trustpilot用来标识评论的固定属性,不会随前端更新轻易变更。 - 相对路径匹配:在每个评论容器内使用
.//开头的相对XPath查找子元素,确保评论内容与分数严格一一对应,避免因元素数量不匹配导致的错误。 - 0票场景处理:如果评论没有有用性投票元素,直接赋值0;如果有元素,从文本中提取数字,无数字的情况也视为0票。
- 变量修复:修正原代码中
usefulness未初始化、helpfulness未定义的问题,统一使用helpfulness_scores存储结果。
自定义适配提示
如果本地HTML文件的元素结构有变化,可手动检查页面:找到有用性标签的稳定属性(比如类名前缀、aria-label),调整XPath中contains(@class, "xxx")的匹配内容,只保留固定前缀即可忽略动态生成的后缀。
内容的提问来源于stack exchange,提问作者ThijsZ
相关产品推荐
相关产品推荐

