【问题标题】:Python BeautifulSoup Looping Through Table DataPython BeautifulSoup 循环遍历表数据
【发布时间】:2019-01-17 14:38:58
【问题描述】:

这里对 Python 非常陌生。我正在尝试从此页面this page 捕获一些数据。我正在尝试获取两个列表中捕获的项目名称和项目类型。稍后我可以弄清楚如何将它们加入一张桌子。任何帮助都会很棒!

代码行自己工作,但循环对我不起作用。 这样就成功生成了两行代码:

import urllib
import bs4 as bs

sauce = urllib.request.urlopen('https://us.diablo3.com/en/item/helm/').read()
soup = bs.BeautifulSoup(sauce, 'lxml')

item_details =  soup.find('tbody')
print(item_details) 

item_name = item_details.find('div', class_='item-details').h3.a.text
print(item_name)

item_type = item_details.find('ul', class_='item-type').span.text
print(item_type)

这会一遍又一遍地重复第一个 item_name 的值:

for div in soup.find_all('div', class_='item-details'):
    item_name = item_details.find('div', class_='item-details').h3.a.text
    print(item_name)
    item_type = item_details.find('ul', class_='item-type').span.text
    print(item_type)

这是输出:

Veil of Steel
Magic Helm
Veil of Steel
Magic Helm
Veil of Steel
Magic Helm
Veil of Steel
Magic Helm
Veil of Steel
Magic Helm
Veil of Steel
Magic Helm
Veil of Steel
Magic Helm
...

【问题讨论】:

    标签: python web-scraping beautifulsoup


    【解决方案1】:

    您需要使用find_all(返回列表)而不是find(返回单个元素):

    for i, j in zip(item_details.find_all('div', class_='item-details'), item_details.find_all('ul', class_='item-type')):
        print(i.h3.a.text, " - ", j.span.text)
    

    输出是:

    Veil of Steel  -  Magic Helm
    Leoric's Crown  -  Legendary Helm
    Harlequin Crest  -  Magic Helm
    The Undead Crown  -  Magic Helm
    ...
    

    或更易读的格式:

    names = item_details.find_all('div', class_='item-details')
    types = item_details.find_all('ul', class_='item-type')
    
    for name, type in zip(names, types):
        print(name.h3.a.text, " - ", type.span.text)
    

    【讨论】:

    • 这太棒了!如何在 2xn 矩阵中显示结果而不是连接它们?
    • @Lucas ,您希望输出是什么样的?你能分享例子吗?
    • 我最终会将其导出到一个 csv 文件,所以我想要两列,一列包含 item_name 和下面的所有值,然后一列包含 item_type 和下面的值。
    • @Lucas,你的意思是name_list = [name.h3.a.text for name in names]type_list = [type.span.text for type in types]?这将返回两个单独的名称和类型列表
    • 我想我真正要问的是如何以准备导出到 csv 的格式获取它。 csv 将包含两列(如具有两列的 excel 文件)。我不想打印名称,而是希望将它们写入数据框(?)。
    【解决方案2】:

    您可以在详细信息部分的一个循环中执行此操作,而不是将它们保存在不同的列表中并匹配它们

    item_details = []
    for sections in soup.select('.item-details'):
        item_name = sections.select_one('h3[class*="subheader-"]').text.strip()  # partial match subheader-1, subheader-2, ....
        item_type = sections.select_one('ul[class="item-type"]').text.strip()
        item_details.append([item_name, item_type])
    
    print(item_details)
    

    输出

    [['钢铁面纱', '魔法头盔'], [“李奥瑞克的王冠”, '传奇头盔'], ....

    【讨论】:

    • 感谢托比。也正确,但另一个答案对我来说更直观。
    【解决方案3】:

    这行得通:

    sauce = urllib.request.urlopen('https://us.diablo3.com/en/item/helm/').read()
    soup = bs.BeautifulSoup(sauce, 'lxml')
    
    item_names = soup.find_all('div', class_='item-details')
    for ele in item_names:
       print(ele.h3.a.text)
    
    item_type = soup.find_all('ul', class_='item-type')
    for ele in item_type:
        print(ele.span.text)
    

    为什么您的代码不起作用:

    看起来您的代码不是遍历所有元素,而是不断获取相同的元素(所有元素的 find_all)。

    【讨论】:

    • 嘿。当我开始写我的时,你的答案没有发布。我花了一些时间检查我的代码是否有效,我认为您当时已经发布了答案。但是是的,几乎是一样的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-29
    • 2018-10-22
    • 2012-08-25
    • 1970-01-01
    • 2012-05-05
    • 2018-10-26
    相关资源
    最近更新 更多