【问题标题】:BeautifulSoup joining two tables(rows) to generate the csv fileBeautifulSoup 连接两个表(行)以生成 csv 文件
【发布时间】:2020-09-04 08:47:42
【问题描述】:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import csv

html = urlopen(
    "https://www.accessdata.fda.gov/scripts/drugshortages/default.cfm")
bsObj = BeautifulSoup(html, "lxml")
table = bsObj.find('table', id="cont")
rows = table.findAll("tr")


links =  [a['href'] for a in table.find_all('a', href=True) if a.text]
new_links = []
for link in links:
    new_links.append(("https://www.accessdata.fda.gov/scripts/drugshortages/"+link).replace(" ", "%20"))
href_rows = []
for link in new_links:   
    link = link.replace("®", "%C2%AE")
    html = urlopen(link)
    bsObj_href = BeautifulSoup(html, "lxml")
    #bsObj_href = BeautifulSoup (html.decode('utf-8', 'ignore'))
    div_href = bsObj_href.find("div",{"id":"accordion"})
    href_rows.append(div_href.findAll("tr"))


csvFile = open("drug_shortage.csv", 'wt', newline='')
writer = csv.writer(csvFile)
try:
    for row in rows:
        csvRow = []
        for cell in row.findAll(['td', 'th']):
            csvRow.append(cell.get_text())
        writer.writerow(csvRow)

finally:
    csvFile.close()

你好,所以我创建了两个这样的行。如果你去这个网站https://www.accessdata.fda.gov/scripts/drugshortages/default.cfm 他们有药物名称和状态列,当您单击药物名称时,您可以找到另外四个列。我喜欢按顺序组合在一起(基于药物名称) 所以这将是药物名称、状态、介绍、可用性和估计的短缺持续时间、相关信息、短缺原因(根据 FDASIA)。 但目前的代码只生成第一个(药物名称,状态)。 我试过了

for row in rows,rows_href:

然后我得到 AttributeError: ResultSet object has no attribute 'findAll'。我得到同样的错误

for row in rows_href:

任何建议我如何生成我想要的?

【问题讨论】:

  • 如果有任何不清楚的地方需要更多解释,请告诉我!
  • 您可能需要for row, link in zip(rows,rows_href) 或者您需要直接在循环中执行 - append( [row, div_href.findAll("tr")] ) 但它需要工作不那么混乱并使用for row in rows: 在每一行中单独搜索链接。跨度>
  • 其他页面有很多行 - 所以可能你必须用相同的 name, status 保存每一行,它需要额外的 for 循环。它只表明您创建的代码过于混乱,您应该单独处理主页上的每一行。
  • @furas 非常感谢!我还有一个问题,如果我想创建列名(药物名称、状态、演示文稿...),我该怎么做?因为目前第一个药物是列名。我想如果我做 [0:] 或不放任何东西不会跳过标题,但它只会给我索引错误。

标签: python python-3.x csv beautifulsoup


【解决方案1】:

你的代码太乱了。

您获取所有行,接下来是所有链接,然后您尝试获取所有其他信息,但这样您无法控制要加入行的值。最大的问题是当某些行在子页面上没有数据并且您的所有数据将移动到上一行时。

您应该从主页上的表格中获取所有行,然后使用for-loop 分别处理每一行以仅获取该单行的其他元素 - 仅读取该行的链接,仅从子页面获取该行的数据等,并将该行的所有数据作为子列表[name, status, link, presentation, availability, related, reason] 放在列表中。之后,您将获得下一项工作,并且只使用下一行的数据。

顺便说一句:因为子页面可能有很多行,所以我在data 中创建了很多行,名称、状态相同,但其他值不同

 [name, status, values from first row on subpage]
 [name, status, values from second row on subpage]
 [name, status, values from string row on subpage]

from urllib.request import urlopen
from bs4 import BeautifulSoup
import csv

html = urlopen("https://www.accessdata.fda.gov/scripts/drugshortages/default.cfm")
bsObj = BeautifulSoup(html, "lxml")

# list for all rows with all values
data = []

# get table on main page
table = bsObj.find('table', {'id': 'cont'})

# work with every row separatelly
for row in table.find_all("tr")[1:]:  # use `[1:]` to skip header
    # get columns only in this row
    cols = row.find_all('td')

    # get name and url from first column
    link = cols[0].find('a', href=True)
    name = link.text.strip()
    url  = link['href']
    url = "https://www.accessdata.fda.gov/scripts/drugshortages/" + url
    url = url.replace(" ", "%20").replace("®", "%C2%AE")
    print('name:', name)
    print('url:', url)

    # get status from second column
    status = cols[1].text.strip()
    print('status:', status)

    # subpage 
    html = urlopen(url)
    bsObj_href = BeautifulSoup(html, "lxml")
    subtable = bsObj_href.find("table")
    if not subtable:
        data.append([name, status, link, '', '', '', ''])
        print('---')
    else:
        for subrows in subtable.find_all('tr')[1:]:   # use `[1:]` to skip header
            #print(subrows)
            subcols = subrows.find_all('td')
            presentation = subcols[0].text.strip()    
            availability = subcols[1].text.strip()    
            related = subcols[2].text.strip()    
            reason = subcols[3].text.strip()    
            data.append([name, status, link, presentation, availability, related, reason])
            print(presentation, availability, related, reason)
            print('---')

    print('----------')


with open("drug_shortage.csv", 'wt', newline='') as csvfile:
    writer = csv.writer(csvFile)

    # write header - one row - using `writerow` without `s` at the end
    #writer.writerow(['Name', 'Status', 'Link', 'Presentation', 'Availability', 'Related', 'Reason'])

    # write data - many rowr - using `writerows` with `s` at the end
    writer.writerows(data)

# no need to close because it use `with`

【讨论】:

  • 非常感谢!我还有一个问题,如果我想创建列名(药物名称、状态、演示文稿...),我该怎么做?因为目前第一个药物是列名。
  • 我想如果我做 [0:] 或不放任何东西不会跳过标题,但它只会给我索引错误。
  • 您必须跳过从 HTML 获得的第一行,因为它没有数据,只有表格的标题,这对您没有用处。如果要在文件中添加标题,请在答案writer.writerow(['Name', 'Status', 'Link', 'Presentation', 'Availability', 'Related', 'Reason']) 中使用注释行
猜你喜欢
  • 1970-01-01
  • 2021-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-03
  • 2014-11-10
  • 2016-08-12
  • 1970-01-01
相关资源
最近更新 更多