【问题标题】:Scraping with BeautifuldSoup to csv用 BeautifulSoup 抓取到 csv
【发布时间】:2022-01-16 20:42:21
【问题描述】:

此代码在我运行时不会崩溃。输出文件 flyingmag.cs​​v 已填充,但不是我想要的。我想添加 div class="elementor-widget-container" > h2div class="elementor-widget-container" > h3 以便飞机制造商和飞机模型包含在输出中。 我真的希望记录采用传统的 excel row 格式,以及刮所有飞机制造商和型号

import requests, csv
from bs4 import BeautifulSoup
from urllib.request import Request

url = 'https://www.flyingmag.com/2019-buyers-single-engine-piston/'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'}

with open('flyingmag.csv', "w", encoding="utf-8-sig") as f:
    writer = csv.writer(f)    
    writer.writerow(['Base_Price','Typically_Equipped_Price','Engine','Horsepower','Propeller','Seats','Length','Height','Wingspan','Wing_Area','Wing_Loading','Power_Loading','Max_Takeoff_Weight','Empty_Weight','Useful_Load','Fuel_Capacity','Max_Operating_Altitude','Max_Rate_of_Climb','Max_Cruise_Speed','Normal_Cruise_Speed','Never_Exceed_Speed','Stall_Speed-Flaps_Up','Stall_Speed-Landing_Configuration','Max_Range','Takeoff_Roll','Takeoff_Distance_Over_50_ft.','Landing_Roll','Landing_Distance_Over_50_ft'])

    while True:
        html = requests.get(url , headers = headers)
        soup = BeautifulSoup(html.text, 'html.parser')
      
        for row in soup.select('table tbody tr'):
            writer.writerow([c.text if c.text else '' for c in row.select('td')])
            print(row)
        else:
            break

【问题讨论】:

  • 停止使用标签发送垃圾邮件。您的代码中没有pandas,页面没有分页。

标签: python csv web-scraping beautifulsoup


【解决方案1】:

您可以首先通过查找 h3 标头(我使用 section:has([data-widget_type="heading.default"]) 执行此操作)来计算总体“部分”或我称之为列表的数量,然后循环这些并提取制造商。使用find_next 移动到包含模型和表格的实际以下部分。如果向下滚动到底部,所有数据似乎都显示在该页面上。

关于标题:

td:not([colspan]) strong

:not([colspan]) 用于排除每个列表的每个列表的最后一个 Back to Top 行。这是一个带有colspan 属性的“合并单元格”,不包含您想要的数据。您也可以使用nth-child range 选择器。第一个(或查看页面时最左边的)和第三个表格列用于标题,我只为第一个列表访问这些列。我检查了这些相同的标题最初是否存在于所有表中。 空格 strong 然后选择后代strong 元素,这些元素存在于表格每一行中的第一个和第三个td 子元素。

关于 csv 中标题后的行值:

td:not([colspan]):nth-child(even)

第一部分是根据标题的解释。但是,我没有使用strong 类型选择器添加后代组合器,而是简单地使用了nth-child(even);这会根据需要为第 2 列和第 4 列选择,因为它们是偶数编号的子项。


import requests, csv
from bs4 import BeautifulSoup as bs

r = requests.get('https://www.flyingmag.com/2019-buyers-single-engine-piston')
soup = bs(r.content, 'lxml')
listings = soup.select('section:has([data-widget_type="heading.default"])')

with open('flyingmag.csv', "w", encoding="utf-8-sig", newline='') as f:
    
    writer = csv.writer(f, delimiter = ",", quoting=csv.QUOTE_MINIMAL)    
    
    for num, listing in enumerate(listings):
        
        manufacturer = listing.select_one('[data-widget_type="heading.default"] h2').text
        model = listing.find_next('h3').text
        table = listing.find_next('table')
        
        if num == 0:
            
            row = ['Manufacturer', 'Model']
            row.extend([i.text for i in table.select('td:not([colspan]) strong')])
            writer.writerow(row)
        
        values = [i.text for i in table.select('td:not([colspan]):nth-child(even)')]
        row = [manufacturer, model]
        row.extend(values)
        writer.writerow(row)

【讨论】:

  • 亲爱的 QHarr,非常感谢您的洞察力。我添加了“从 bs4 导入 BeautifulSoup 作为 bs”。由于缺少两个新字段,只有标题没有对齐。
  • 哦,很抱歉...我会尽快修改
  • 非常感谢,这太棒了。
猜你喜欢
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
  • 2014-06-20
  • 2020-09-02
  • 1970-01-01
  • 2014-08-26
  • 1970-01-01
  • 2016-01-01
相关资源
最近更新 更多