【发布时间】:2020-11-26 21:28:34
【问题描述】:
我正在抓取tripadvisor。我现在的问题是抓取给定酒店的Hotelstars(不是平均用户评分[气泡],而是酒店等级评分),我稍后会遇到评论被隐藏在“阅读更多”后面的问题。 https://www.tripadvisor.com.ph/Hotel_Review-g8762949-d1085145-Reviews-El_Rio_y_Mar_Resort-San_Jose_Coron_Busuanga_Island_Palawan_Province_Mimaropa.html 幸好我知道数据在哪里可以找到两者。它在这个标签内的页面中:
<script window.__WEB_CONTEXT={pageManifest:{"assets":[....
....
</script>
在此处搜索 https://pastebin.com/Ww3ugxFR 以获取“景色太棒了!!” (隐藏文本示例)或 Hotelstars 的 '"star":'。
我想学习如何访问这个标签。
这是我如何不起作用的示例。我需要学习如何告诉 CSS 选择器(或其他工具)如何解决这个特定问题以及如何从中提取数据。在此示例中,我将仅加载响应并进行简单的模式搜索。我想也可以用 Json 加载它并从那里提取,但我还没有确定 Json。:
hotel_CONTEXT = response.css("script text=window.__WEB_CONTEXT ::attr(pageManifest)).extract()
pattern_hotelstar = re.compile(r'star":\["\d')
matches_hotelstar = pattern_hotelstar.findall(hotel_CONTEXT)
Hotel_stars = str(matches_hotelstar).split('"')[2].split("'")[0]
显然,我想通过 BeautifulSoup 实现我想要实现的目标(Scraping a website with data hidden under "read more" ...但是我在尝试复制时遇到了 json 错误),但通常我更喜欢使用 Scrapy 的解决方案。
Andrej Kesely 为我的问题提供了出色的解决方案!他的代码运行良好,我想完全理解它!以下是我认为从代码中理解的内容以及我不理解他的巫术的地方;):
data = re.search(r'window\.__WEB_CONTEXT__=(.*?});', html_text).group(1)
Andrej 在整个 html_text 中搜索以“window.__WEB...”开头的模式,将模式扩展到所有字符 (.),以非贪婪方式 (?) 任意次数 (*)并以“;”结尾。我不明白为什么会有一个带有 } init 的捕获组,以及为什么 } 不只是放在最后,因为脚本以 } 结尾; (Andrej 是如何发现这一点的?这是这些的一般模式还是他打印了整个页面并进行了查找?)。我也不明白为什么它必须是非贪婪的。 Group(1) 选择了离开窗口的第一个括号内的所有内容。WEB_CONTEXT= out。我想这与使用 json 加载结果有关。也一样
data = data.replace('pageManifest', '"pageManifest"')
然后,Andrej 创建了一个名为 traverse 的函数,该函数稍后将填充数据的输出。在 if 语句中,Andrej 检查输入是否是字典。在下一步中,Andrej 循环遍历字典的 key(k) 和 value(v)。如果 k=="reviews" 他产生价值。如果不是“从功能中获得收益”?我也迷失了 elif 和检查 val 是否是一个列表......一般来说,函数的输出 v 是什么?我将如何更改函数以包含更多要滚动的字典,因为 else 已被此 yield from 占用。
def traverse(val):
if isinstance(val, dict):
for k, v in val.items():
if k == 'reviews':
yield v
else:
yield from traverse(v)
elif isinstance(val, list):
for v in val:
yield from traverse(v)
这里 Andrej 循环遍历 traverse(data)(字典,对吗?)。由于我们在此页面上收到了多条评论。 在嵌套循环中,Andrej 为单个评论中的每个字典命名为 r,并通过 dictonary_name["key"] 检索存储的值。我说的对吗?
for reviews in traverse(data):
for r in reviews:
print(r['userProfile']['displayName'])
print(r['title'])
print(r['text'])
print('Rating:', r['rating'])
print('-' * 80)
抱歉所有这些新手问题。
【问题讨论】:
-
您能否提供一些代码作为上下文并解释您的数据需求是什么。看起来您想要此网站页面上的评论和酒店星级?
-
嗨@AaronS,我希望我的问题现在更清楚了。我想我的问题基本上可以归结为:如何在没有任何类的情况下访问脚本标签。其他人显然可以用 BeautifulSoup(见链接)做到这一点,但我在他们的代码上遇到了问题,通常我会更乐意使用 Scrapy 完成所有事情。
标签: python web-scraping beautifulsoup scrapy tripadvisor