【问题标题】:how to preserve links when scraping a table with beautiful soup and pandas用漂亮的汤和熊猫刮桌子时如何保留链接
【发布时间】:2017-07-06 05:47:15
【问题描述】:

使用Beautiful soupPandas 抓取网页以获取表格。其中一列有一些网址。当我将 html 传递给 pandas 时,href 丢失了。

有没有办法只保留该列的 url 链接?

示例数据(经过编辑以更好地适用于案例):

  <html>
        <body>
          <table>
              <tr>
               <td>customer</td>
               <td>country</td>
               <td>area</td>
               <td>website link</td>
             </tr>
             <tr>
               <td>IBM</td>
               <td>USA</td>
               <td>EMEA</td>
               <td><a href="http://www.ibm.com">IBM site</a></td>
            </tr>
          <tr>
            <td>CISCO</td>
            <td>USA</td>
            <td>EMEA</td>
            <td><a href="http://www.cisco.com">cisco site</a></td>
         </tr>
           <tr>
            <td>unknown company</td>
            <td>USA</td>
            <td>EMEA</td>
            <td></td>
         </tr>
       </table>
     </body>
  </html>

我的python代码:

    file = open(url,"r")

    soup = BeautifulSoup(file, 'lxml')

    parsed_table = soup.find_all('table')[1] 

    df = pd.read_html(str(parsed_table),encoding='utf-8')[0]

 df

输出(导出为 CSV):

customer;country;area;website
IBM;USA;EMEA;IBM site
CISCO;USA;EMEA;cisco site
unknown company;USA;EMEA;

df 输出正常,但链接丢失。我需要保留链接。至少是 URL。

有什么提示吗?

【问题讨论】:

    标签: python pandas beautifulsoup


    【解决方案1】:

    pd.read_html 假定您感兴趣的数据在文本中,而不是标签属性中。但是,自己刮桌子并不难:

    import bs4 as bs
    import pandas as pd
    
    with open(url,"r") as f:
        soup = bs.BeautifulSoup(f, 'lxml')
        parsed_table = soup.find_all('table')[1] 
        data = [[td.a['href'] if td.find('a') else 
                 ''.join(td.stripped_strings)
                 for td in row.find_all('td')]
                for row in parsed_table.find_all('tr')]
        df = pd.DataFrame(data[1:], columns=data[0])
        print(df)  
    

    产量

              customer country  area          website link
    0              IBM     USA  EMEA    http://www.ibm.com
    1            CISCO     USA  EMEA  http://www.cisco.com
    2  unknown company     USA  EMEA                      
    

    【讨论】:

    • KeyError: 'href' ,似乎并非所有行都有链接 unutbu
    • ""tag[key] 返回标签的 'key' 属性的值,如果不存在则抛出异常。"""
    • 如果使用合并单元格,如 col span 或 row span > 1,则不起作用
    【解决方案2】:

    这样检查标签是否存在:

     import numpy as np
    
     with open(url,"r") as f:
         sp = bs.BeautifulSoup(f, 'lxml')
         tb = sp.find_all('table')[56] 
         df = pd.read_html(str(tb),encoding='utf-8', header=0)[0]
         df['href'] = [np.where(tag.has_attr('href'),tag.get('href'),"no link") for tag in tb.find_all('a')]
    

    【讨论】:

      【解决方案3】:

      如果您要从 html 表中获取多个链接,这是另一种方法。我宁愿使用单独的 for 循环而不是进行列表理解,这样代码对于那些不熟悉 python 的人来说更具可读性,并且如果出现错误,更容易调整代码或处理错误。我希望它会对某人有所帮助。

      soup = BeautifulSoup(html, "lxml")
      table = table.find('table')
      thead = table.find('thead')
      column_names = [th.text.strip() for th in thead.find_all('th')]
      
      data = []
      for row in table.find_all('tr'):
          row_data = []
          for td in row.find_all('td'):
              td_check = td.find('a')
              if td_check is not None:
                  link = td.a['href']
                  row_data.append(link)
              else:
                  not_link = ''.join(td.stripped_strings)
                  if not_link == '':
                       not_link = None
                  row_data.append(not_link)
          data.append(row_data)
      df = pd.DataFrame(data[1:], columns=column_names)
      df_dict = df.to_dict('records')
      
      for row in df_dict:
          print(row)
      

      【讨论】:

      • 如果有多个表使用:table = soup.find_all('table')[1] 其中 [1] 是您感兴趣的表的索引。
      猜你喜欢
      • 2017-12-23
      • 1970-01-01
      • 2013-11-08
      • 2018-01-13
      • 2017-09-17
      • 1970-01-01
      • 2021-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多