【问题标题】:beautiful soup to csv漂亮的汤到 csv
【发布时间】:2015-11-19 18:44:39
【问题描述】:

有几个线程将漂亮的汤数据转换为 csv 文件,但我找不到一个对我的代码有意义的线程。

我正在从《华尔街日报》的最大赢家中挖角。 3 到 103 为我提供了一天内排名前 100 的股票。

在单独的单元格中获取表格中每一行的值时遇到问题。每行应该有 6 个包含数据的单元格。然后它应该转到下一行并给我接下来的 6 个数据点(下一个股票)。

每当我使用下面的方法时,它只会在 WSJ 股票上输出一行,而不是循环多次并每次都转到下一行。我不确定前 6 个 td 标签在第 1 行,然后接下来的 6 个 td 标签在第 2 行。

我尝试通过修改 symbol.text 创建一个名为单元格的列表,但没有成功。

将第一行的所有值都放在第一个 tr 标签中会更容易,因为它们有六个,但它们需要在自己的单元格中。我也试过循环这个也没有运气。

我是 Python 新手,所以最好使用最简单的代码。

import requests
from bs4 import BeautifulSoup
import csv

urlList = ['http://online.wsj.com/mdc/public/page/2_3021-gainnyse-gainer.html',
       'http://online.wsj.com/mdc/public/page/2_3021-gainnyse-gainer--20150806.html?mod=mdc_pastcalendar',
       'http://online.wsj.com/mdc/public/page/2_3021-gainnyse-gainer--20150805.html?mod=mdc_pastcalendar',
       'http://online.wsj.com/mdc/public/page/2_3021-gainnyse-gainer--20150804.html?mod=mdc_pastcalendar',
       'http://online.wsj.com/mdc/public/page/2_3021-gainnyse-gainer--20150803.html?mod=mdc_pastcalendar']



for i in range(len(urlList)):
    url = urlList[i]            
    r = requests.get(url)
    soup = BeautifulSoup(r.content)         
    scrapeData = soup.select('tr')[3:103]    
    for symbol in scrapeData: 
       print(symbol.text)  



outputFile = open('wsjExample.csv', 'w')          
outputWriter = csv.writer(outputFile)
outputWriter.writerow(['Number', 'Symbol', 'Price', 'Change', '% Change', 'Volume'])
for row in range(len(scrapeData)):
    outputWriter.writerow([symbol('td')[0].text, symbol('td')[1].text, symbol('td')[2].text, symbol('td')[3].text, symbol('td')[4].text, symbol('td')[5].text])
outputFile.close()

谢谢,

【问题讨论】:

  • 您能否提供一个完整的最低工作示例并修复您的代码格式?您至少应该为 url 提供所需的数据并修复缩进。你在哪里绊倒了exaclty?你能正确地从网页中提取数据吗?
  • 好的,我已经修复了格式并添加了所有代码。我能够提取数据没有问题。当我运行这个程序时,它会一遍又一遍地导出同一行,而不是导出下一行数据。
  • 我只是看了一下网页的html代码。您是否知道包含您的数据的整个表都在类 mdcTable 的 div 容器中?因此,要获取表格,您可以使用table = soup.find("table", { "class": "mdcTable" })

标签: python html csv beautifulsoup


【解决方案1】:

问题是您在迭代数据的循环之外引用symbol('td')。您实际上在做的是:

scrapeData=[...] # list of the scraped data

for symbol in scrapeData:
    print symbol

# symbol is now set to the last item in scrapeData
# open file etc..
# for row in scrapeData length - do this next action that many times:
print symbol('td')[0] # this will print the first element in the symbol, which is the last element in scrapeData - there is no connection to the row at all.

您需要做的是在您的第一个循环中通过 scrapeData 刮取值 - 将其放入临时列表中。然后在写入 CSV 文件时遍历列表。

【讨论】:

    【解决方案2】:

    .find('table', {'class' : 'mdcTable'}) 可以访问给定 URL 下提供的表格,正如我在 comment above 中所述。需要忽略表的第一行,因为这是标题并且不包含正确的数据(将标题提取为列名的一点“智能”实现会很好,但我还没有实现类似的东西)这是由[1:]for row in table.findAll('tr')[1:] 中完成。

    为了分离数据提取和 csv 导出,我将所有提取的数据存储到字典 d 中,该字典附加到名为 data 的列表中。所有提取的值都以适当的方式格式化为具有整数、浮点数和字符串等,并删除不需要的换行符或逗号。

    在收集所有数据、存储在 dicts 中并附加到 data 列表后,使用 DictWriter 和适当的 .writeheader().writerows() 方法将整个列表写入 csv 文件:

    #!/usr/bin/env python3
    # coding: utf-8
    
    import csv
    import urllib.request
    from bs4 import BeautifulSoup
    
    html = urllib.request.urlopen('http://www.wsj.com/mdc/public/page/2_3021-gainnyse-gainer.html')
    soup = BeautifulSoup(html, 'html.parser')
    table = soup.find('table', {'class' : 'mdcTable'})
    
    data = []
    
    for row in table.findAll('tr')[1:]:
        col = row.findAll('td')
    
        d = {    
                'rank' : col[0].getText(),
                'issue': col[1].getText(),
                'price' : col[2].getText(),
                'change' : col[3].getText(),
                'per_change' : col[4].getText(),
                'volume' : col[5].getText()
            }
    
        for key, val in d.items():
            val = val.replace('\n', '')
            val = val.replace(',', '')
            d[key] = val
    
            try:
                if key not in  ['rank', 'volume']:
                    d[key] = float(val)
                else:
                    d[key] = int(val)
            except Exception as e:
                pass
    
        data.append(d)
    
    order = ['rank', 'issue', 'price', 'change', 'per_change', 'volume']
    
    with open('output.csv', 'w') as f:
        writer = csv.DictWriter(f, fieldnames=order)
        writer.writeheader()
        writer.writerows(data)
    

    【讨论】:

      【解决方案3】:

      这是如何写入 csv 文件:

      import csv
      
      with open('names.csv', 'w') as csvfile:
          fieldnames = ['first_name', 'last_name']
          writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
      
      writer.writeheader()
      writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})
      writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})
      writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})
      

      【讨论】:

        猜你喜欢
        • 2020-01-20
        • 2016-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-10
        相关资源
        最近更新 更多