【问题标题】:Webscraping Issue w/ BeautifulSoup带有 BeautifulSoup 的网页抓取问题
【发布时间】:2020-07-18 11:47:24
【问题描述】:

我是 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'):

我没有得到所有评论,我只是一遍又一遍地得到相同的条目。

任何帮助将不胜感激。

谢谢!

【问题讨论】:

  • 您用来识别评论的 CSS 类不正确。例如,loadingOverlay_24D 不是包含div 的评论

标签: python web web-scraping


【解决方案1】:

问题一:循环内重复数据

你的循环有以下形式:

for div in soup.find('div' , ...):
    name = soup.find('h4', ... )
    policy = soup.find('div', ... )
    ...

请注意,您在 soup 对象的循环内调用了 find。这意味着每次您尝试查找 name 的值时,它都会从头开始搜索整个文档并在每次迭代中返回第一个匹配项。

这就是为什么您一遍又一遍地获得相同数据的原因。

要解决此问题,您需要在您当前所在的当前评论 div 中调用 find。那就是:

 for div in soup.find('div' , ...):
    name = div.find('h4', ... )
    policy = div.find('div', ... )
    ...

问题 2:缺失数据和错误处理

在您的代码中,循环内的任何错误都会被忽略。但是,在解析和提取值时实际发生了许多错误。例如:

    location = div.find('h4').find('small').text

并非所有评论都有位置信息。因此,代码将提取h4,然后尝试查找small,但没有找到,返回None。然后您在该 None 对象上调用 .text,导致异常。因此,此评论不会添加到结果数据框中。

要解决此问题,您需要添加更多错误检查。例如:

  locationDiv = div.find('h4').find('small')
  if locationDiv:
      location = locationDiv.text
  else:
      location = ''

问题 3:识别和提取数据

您尝试解析的页面的 HTML 已损坏,并且使用了看似随机或至少不一致的 CSS 类。您需要为要提取的数据找到正确且唯一的标识符,以便它们严格匹配所有条目。

例如,您正在使用 CSS 类 loadingOverlay_24D 提取评论容器 div。这是不正确的。这个 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
...

【讨论】:

  • 非常感谢阿齐兹,详尽的解释。我正在研究您的解决方案。
【解决方案2】:

页面提供损坏的 html 代码,html.parser 更擅长处理它。

soup = bs(r.text, 'lxml') 更改为soup = bs(r.text, 'html.parser')

【讨论】:

  • 页面肯定坏了,但这根本不会改变结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-07
  • 2021-01-07
  • 1970-01-01
相关资源
最近更新 更多