【问题标题】:Scraping table (several pages) to Pandas Dataframe将表(几页)抓取到 Pandas Dataframe
【发布时间】:2021-06-07 19:01:51
【问题描述】:

我正在尝试将长表 (24 页) 的数据传输到 Pandas 数据框,但遇到 (我认为) 的一些问题 -循环代码。

import requests
from bs4 import BeautifulSoup
import pandas as pd

base_url = 'https://scrapethissite.com/pages/forms/?page_num={}'
res = requests.get(base_url.format('1'))
soup = BeautifulSoup(res.text, 'lxml')

table = soup.select('table.table')[0]
columns = table.find('tr').find_all('th')
columns_names = [str(c.get_text()).strip() for c in columns]
table_rows = table.find_all('tr', class_='team')

l = []
for n in range(1, 25):
    scrape_url = base_url.format(n)
    res = requests.get(scrape_url)
    soup = BeautifulSoup(res.text, 'lxml')
    for tr in table_rows:
        td = tr.find_all('td')
        row = [str(tr.get_text()).strip() for tr in td]
        l.append(row)

df = pd.DataFrame(l, columns=columns_names)

Dataframe 仅作为第一页的重复出现,而不是表中所有数据的副本。

【问题讨论】:

  • table_rows 设置在 for 循环之外,因此不会在循环内更改。这是你的问题吗?
  • 它自己不起作用,但@Corralien 的解决方案起作用了。谢谢。
  • 仅供参考 pandas read_html 允许直接从 url 加载 html 表格。
  • @RJAdriaansen 我一定会尝试一下,但我尝试这段代码的目的是练习网页抓取作为一个概念,我只是添加了 Pandas 部分以使其更难。谢谢。

标签: python pandas beautifulsoup


【解决方案1】:

我同意@mxbi。

试试看:

import requests
from bs4 import BeautifulSoup
import pandas as pd

base_url = 'https://scrapethissite.com/pages/forms/?page_num={}'

l = []
for n in range(1, 25):
    scrape_url = base_url.format(n)
    res = requests.get(scrape_url)
    soup = BeautifulSoup(res.text, 'lxml')

    table = soup.select('table.table')[0]
    columns = table.find('tr').find_all('th')
    columns_names = [str(c.get_text()).strip() for c in columns]
    table_rows = table.find_all('tr', class_='team')

    for tr in table_rows:
        td = tr.find_all('td')
        row = [str(tr.get_text()).strip() for tr in td]
        l.append(row)

df = pd.DataFrame(l, columns=columns_names)

【讨论】:

  • 看起来不错,我一开始尝试了@mxbi 的建议,但没有奏效,但这确实奏效了。你能通过在for循环之前分配变量来向我解释我做错了什么吗?我是初学者,这对我很有帮助,谢谢。
  • 循环外的代码只执行一次,而您需要在每次迭代中更新一些部分。在您的情况下,您需要在每次获得新页面时更新tablecolumnscolumns_namestable_rows
【解决方案2】:

requests 是必需的,因为服务器需要一个用户代理标头,而 pandas read_html 不允许这样做。由于您仍然想使用 pandas 来生成数据帧,因此您可以通过使用多处理来处理请求并在用户定义的函数中提取感兴趣的表并将其作为字符串传递给 read_html 来获得一些效率。您将获得可以与 pandas concat 结合的数据框列表。

注意:这不能在 Jupyter 中运行,因为会阻塞。

import pandas as pd
from multiprocessing import Pool, cpu_count
import requests
from bs4 import BeautifulSoup as bs

def get_table(url:str)-> pd.DataFrame:
    soup = bs(requests.get(url).text, 'lxml')
    df = pd.read_html(str(soup.select_one('.table')))[0]
    df['page_num'] = url.split("=")[-1]
    return df

if __name__ == '__main__':
    
    urls = [f'https://scrapethissite.com/pages/forms/?page_num={i}' for i in range(1, 25)]

    with Pool(cpu_count()-1) as p:
        results = p.map(get_table, urls)

    final = pd.concat(results)
    print(final)
    # final.to_csv('data.csv', index = False, encoding = 'utf-8-sig')

【讨论】:

    猜你喜欢
    • 2019-07-06
    • 2018-03-17
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    相关资源
    最近更新 更多