【问题标题】:Scraping over multiple pages using BeautifulSoup and dataframe iterrows使用 BeautifulSoup 和 dataframe iterrows 抓取多个页面
【发布时间】:2018-11-11 16:39:43
【问题描述】:

我正在使用 BeautifulSoup 从多个 URL 中抓取。 URL 通过附加一个我保存在数据框 (postcode_URL) 中的变量来迭代。

代码断线:table_rows = table.find_all('tr'),抛出错误:'NoneType' object has no attribute 'find_all'

有趣的是,如果我删除迭代并在 URL 中手动输入单个邮政编码,代码可以完美运行,所以我相信它一定与迭代循环有关。

以下是我使用的代码。有什么想法吗?

scraped_data = []

for x, row in postcodes_for_urls.iterrows():
    page = requests.get("http://myurl"+(row['postcode_URL']))
    soup = BeautifulSoup(page.content, 'html.parser')
    table = soup.find('table')
    table_rows = table.find_all('tr')
    for tr in table_rows:
        td = tr.find_all('td')
        row = [tr.text for tr in td]
        scraped_data.append(row)

pd.DataFrame(scraped_data, columns=["A", "B", "C"])

【问题讨论】:

标签: python dataframe web-scraping beautifulsoup


【解决方案1】:

我调查了这个问题,并在我的笔记本电脑上尝试了几个 sn-ps。

问题不在于 DataFrame ,因为您在循环中一次读取每一行,问题在于 URL,您的程序正确地废弃了其中包含表格的页面并抛出没有元素的邮政编码 URL 的错误。

考虑第一个测试:

我创建了一个没有表格的 HTML 页面:

 <html>
  <head>
     <title>Demo page</title>
  </head>

  <body>
     <h2>Demo without table</h2>
  </body>
</html>

然后我执行下面的python代码:

from bs4 import BeautifulSoup
data = open('table.html').read()
parser = BeautifulSoup(data, 'html.parser')
table = parser.find('table')
rows = table.find_all('tr')
print(rows)

上面的代码由于 NoneType 异常而停止,因为如果在 html 中找不到表格元素,parser.find() 会返回一个 NoneType 对象数据。所以 find_all() 不是 NoneType 对象的方法,因此会抛出错误。

所以我改变了我的 HTML 代码如下:

<html>
<head>
    <title>Demo page</title>
</head>

<body>
    <h2>Demo without table</h2>
    <table>
        <tr>Demo</tr>
    </table>
</body>
</html>

现在 python 代码运行良好,没有任何异常,因为存在 table 元素。

所以结论:

例外是因为 DataFrame 中的一个邮政编码指向一个不包含表格的 URL。所以,我建议你对你的代码做一些小改动:

scraped_data = []

for x, row in postcodes_for_urls.iterrows():
  page = requests.get("http://myurl"+(row['postcode_URL']))
  soup = BeautifulSoup(page.content, 'html.parser')
  table = soup.find('table')
  #add this :
  if table == None :
      continue

  table_rows = table.find_all('tr')
  for tr in table_rows:
    td = tr.find_all('td')
    row = [tr.text for tr in td]
    scraped_data.append(row)

pd.DataFrame(scraped_data, columns=["A", "B", "C"])

【讨论】:

  • 太棒了,现在可以完美运行 - 谢谢您的详细解释。
【解决方案2】:

您只需要检查table_rows,如果它为 None 且不为空,请尝试以下代码。您还可以添加 exception handler 之类的 trycatch 声明以获得最佳实践。它总是因为空行或您正在抓取的实际页面上的异常模式而中断。

scraped_data = []

for x, row in postcodes_for_urls.iterrows():
    page = requests.get("http://myurl"+(row['postcode_URL']))
    soup = BeautifulSoup(page.content, 'html.parser')
    table = soup.find('table')

    if table is not None and len(table.find_all('tr'))>0:
        table_rows = table.find_all('tr')
        for tr in table_rows:
            td = tr.find_all('td')
            row = [tr.text for tr in td]
            scraped_data.append(row)
    else:
        scraped_data.append('EMPTY')

pd.DataFrame(scraped_data, columns=["A", "B", "C"])

【讨论】:

  • 是的,明白了。现在有道理了。谢谢。
猜你喜欢
  • 2014-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 2023-03-20
相关资源
最近更新 更多