首页 > 解决方案 > 如何仅将此网站 HTML 表的第一列和 href 链接刮到 pandas 数据框中?

问题描述

有问题的网站。我想在中间刮掉那个表,只想要第一列(公司名称)加上它的 href 链接。

例如在这里,我只想抓取第一个之间的所有数据<td> </td>并忽略其余三个<td>值。然后使用公司名称创建一个列(在本例中为 1-800-FLOWERS.COM),然后创建第二个带有 href 链接的列 (/Company/1-800-flowerscom)

HTML 的图像

到目前为止我所做的:

url = "http://www.annualreports.com/Companies?search="
html = request.urlopen(url).read().decode('utf8')
soup = BeautifulSoup(html, "html.parser")

df = pd.DataFrame(columns=['Company', 'Href'])

tables = soup.findChildren('table')
my_table = tables[0]
rows = my_table.findChildren(['th', 'tr'])

for row in rows:
    cells = row.findChildren('td')
    for cell in cells:
        value = cell.string
        print(value)

这成功地以这种格式成功提取了所有标签:<td>

打印声明2

现在填充我的 df 列的最有效方法是将我的第二个嵌套循环更改为第 4 步并获取 1 个值然后忽略下一个 3?这对我来说似乎真的很令人费解,有没有更好的方法可以让我直接从源头完成所有这些工作?即只提取<td>所有<tr>s中的第一个值,然后将公司名称和href值分成两个不同的列(对于整个表)

标签: pythonhtmlpandasweb-scraping

解决方案


您可以使用nth-of-type来限制第一列 ( td)。由于节点同时href具有感兴趣的文本和文本,您可以使用列表推导中的元组从同一节点检索两者,然后在最后依靠 pandas 来处理列。我正在使用 bs4 4.7.1。不确定从哪个版本开始支持它,但由于所做的改进,您真的想要最新的 bs4。

import requests
import pandas as pd
from bs4 import BeautifulSoup as bs

r = requests.get('http://www.annualreports.com/Companies?search=')
soup = bs(r.content, 'lxml')
df = pd.DataFrame([(i.text, 'http://www.annualreports.com' + i['href']) for i in soup.select('tbody td:nth-of-type(1) a')], columns = ['Company','Link'])
print(df)

一些解释:

soup.select('tbody td:nth-of-type(1) a')

a选择第一列 ( td)中的所有子标签。tbody是否可以确保使用正确的表格。 tbody,tda类型选择器和基于标签的选择,而中间的空格是后代组合器,这意味着右边要匹配的元素是左边要匹配的元素的子元素。

select返回一个列表。

列表理解

[(i.text, 'http://www.annualreports.com' + i['href']) for i in soup.select('tbody td:nth-of-type(1) a')]

可以重写为:

for i in soup.select('tbody td:nth-of-type(1) a'):
    (i.text, 'http://www.annualreports.com' + i['href']) #tuple that is then added to a final list

当您遍历由;a返回的列表中的每个标签时 select当前节点(a标签)同时具有作为其.text 属性的标题和href作为属性的 。可以如图所示访问属性值。'http://www.annualreports.com'添加前缀以使链接完整(否则它们是相对的并且缺少协议和域)。

该列表被传递给pandas,其中元组列表(我们称之为the_list示例)被解压缩到两列中。的columns参数pd.DataFrame用于命名数据​​框中的列。

df = pd.DataFrame(the_list , columns = ['Company','Link'])  # the_list being the result of the list comprehension

推荐阅读