我不熟悉Python网络抓取,并且正在抓取productreview.com进行审核。以下代码提取了单次审核所需的所有数据:
#Scrape TrustPilot for User Reviews (Rating, Comments)
import pandas as pd
import numpy as np
from bs4 import BeautifulSoup as bs
import json
import requests
import datetime as dt
final_list=[]
url = 'https://www.productreview.com.au/listings/world-nomads'
r = requests.get(url)
soup = bs(r.text, 'lxml')
for div in soup.find('div', class_ = 'loadingOverlay_24D'):
try:
name = soup.find('h4', class_ = 'my-0_27D align-items-baseline_kxl flex-row_3gP d-inline-flex_1j8 text-muted_2v5')
name = name.find('span').text
location = soup.find('h4').find('small').text
policy = soup.find('div', class_ ='px-4_1Cw pt-4_9Zz pb-2_1Ex card-body_2iI').find('span').text
title = soup.find('h3').find('span').text
content = soup.find('p', class_ = 'mb-0_2CX').text
rating = soup.find('div', class_ = 'mb-4_2RH align-items-center_3Oi flex-wrap_ATH d-flex_oSG')
rating = rating.find('div')['title']
final_list.append([name, location, policy, rating, title, content])
except AttributeError:
pass
reviews = pd.DataFrame(final_list, columns = ['Name', 'Location', 'Policy', 'Rating', 'Title', 'Content'])
print(reviews)
但是当我编辑
for div in soup.find('div', class_ = 'loadingOverlay_24D'):
到
for div in soup.findAll('div', class_ = 'loadingOverlay_24D'):
我没有收到所有评论,只是一次又一次地循环访问相同的条目。
任何帮助将不胜感激。
谢谢!
答案 0 :(得分:0)
您的循环格式如下:
for div in soup.find('div' , ...):
name = soup.find('h4', ... )
policy = soup.find('div', ... )
...
请注意,您正在find
对象的循环内调用soup
。这意味着每次您尝试查找name
的值时,它将从头开始搜索整个文档,并在每次迭代中返回第一个匹配项。
这就是为什么要不断获取相同数据的原因。
要解决此问题,您需要在当前所在的当前评论find
内致电div
。那是:
for div in soup.find('div' , ...):
name = div.find('h4', ... )
policy = div.find('div', ... )
...
在您的代码中,循环内的任何错误都将被忽略。但是,在解析和提取值时实际上会发生许多错误。例如:
location = div.find('h4').find('small').text
并非所有评论都有位置信息。因此,代码将提取h4
,然后尝试找到small
,但找不到任何内容,返回None
。然后,您在该.text
对象上调用None
,从而导致异常。因此,此评论不会添加到结果数据框中。
要解决此问题,您需要添加更多错误检查。例如:
locationDiv = div.find('h4').find('small')
if locationDiv:
location = locationDiv.text
else:
location = ''
您要解析的页面的HTML损坏,并使用了看上去随机或至少不一致的CSS类。您需要为要提取的数据找到正确且唯一的标识符,以使它们严格匹配所有条目。
例如,您正在使用CSS类div
提取评论容器loadingOverlay_24D
。这是不正确的。这个CSS类似乎是用于“加载”占位符div或类似的东西。实际评论包含在div
块中,如下所示:
<div itemscope="" itemType="http://schema.org/Review" itemProp="review">
....
</div>
请注意,唯一标识属性是itemProp
属性。您可以使用以下方法提取这些div
块:
soup.find('div', {'itemprop': 'review'}):
类似地,您必须找到要提取的其他数据的正确标识属性,以确保您完全正确地获取所有数据。
还有一件事情,当一个标签具有多个CSS类时,通常只有一个是您要使用的标识属性。例如,对于名称,您具有:
name = soup.find('h4', class_ = 'my-0_27D align-items-baseline_kxl flex-row_3gP d-inline-flex_1j8 text-muted_2v5')
但是实际上,您不需要所有这些类。在这种情况下,第一类足以识别名称h4
块
name = soup.find('h4', class_ = 'my-0_27D')
下面是一个从评论页面提取作者姓名的示例:
for div in soup.find_all('div', {'itemprop': 'review'}):
name = div.find('h4', class_ = 'my-0_27D')
if (name):
name = name.find('span').text
else:
name = '-'
print(name)
输出:
Aidan
Bruno M.
Ba. I.
Luca Evangelista
Upset
Julian L.
Alison Peck
...
答案 1 :(得分:-2)
该页面提供了损坏的html代码,而html.parser更好地处理了它。
将soup = bs(r.text, 'lxml')
更改为soup = bs(r.text, 'html.parser')