【问题标题】:BS4 find sub elements where parent class contains hijackBS4 查找父类包含劫持的子元素
【发布时间】:2021-09-07 07:45:29
【问题描述】:

源页面 = http://bgpstream.com/

要解析的部分:

<tr>
    <td class="event_type">Possible Hijack</td>
    <td class="country">          
</td>
<td class="asn">
    <i>Expected Origin AS:</i> TENETA, UA (AS 47725)<br>
    <i>Detected Origin AS:</i> LANFIBRA TELECOMUNICACOES - EIRELI, BR (AS 269684) 
</td>
    <td class="starttime"> 2021-02-28 15:13:14 </td>
    <td class="endtime">
</td>
    <td class="moredetail"> <a href="/event/268928">More detail</a></td>
</tr>

尝试这样的事情:

evts = soup.find_all('td', class_='event_type')
    for evt in evts:
        if('Hijack' in evt.text):
            asns = evt.find_all('asn')
            for a in asns:
                print(a)

但是,我无法获得所需的输出。

我想以任何格式 csv、空格分隔或行并匹配特定 ASN 获取所有“劫持”元素。

例如,使用 AS ####(上述格式 AS 47725)找到任何劫持:

Expected Origin AS: TENETA, UA (AS 47725)
Detected Origin AS: LANFIBRA TELECOMUNICACOES - EIRELI, BR (AS 269684)
2021-02-28 15:13:14 

^最后一个元素是开始时间

我的想法是获取所有包含 Hijack 文本的 td,然后获取子元素,其中 asn 包含我正在寻找的 AS #####(python 参数输入),然后它将返回三个子元素(子元素)循环中当前元素中的那个。但是,我似乎无法从 hijack evts 集合中获取子元素。对迭代集合有任何帮助吗?

【问题讨论】:

    标签: python parsing web-scraping beautifulsoup


    【解决方案1】:

    find_all() 方法accepts a function。您可以创建一个自定义函数来检查“劫持”是否在类 event_type 中,并检查下一个类(asn) 是否包含您正在寻找的所需的“AS-XXX”。

    import requests
    from bs4 import BeautifulSoup
    
    
    URL = "http://bgpstream.com/"
    soup = BeautifulSoup(requests.get(URL).content, "html.parser")
    
    
    def filter_for_hijack():
        return (
            lambda element: element.name == "td"
            and "event_type" in element.get("class")
            and "Hijack" in element.text.strip()
            # You can specify 'AS-XXX' here
            and "AS 47725" in element.find_next(class_="asn").get_text(strip=True)
        )
    
    
    for tag in soup.find_all(filter_for_hijack()):
        print(tag.find_next(class_="asn").get_text(strip=True, separator=" "))
    

    输出:

    Expected Origin AS: TENETA, UA (AS 47725) Detected Origin AS: LANFIBRA TELECOMUNICACOES - EIRELI, BR (AS 269684)
    Expected Origin AS: TENETA, UA (AS 47725) Detected Origin AS: LANFIBRA TELECOMUNICACOES - EIRELI, BR (AS 269684)
    

    【讨论】:

      【解决方案2】:

      您可以使用:has:-soup-contains(或者对于早期版本仅使用:contains)来隔离第一个子td 包含您的目标词的行。一个嵌套列表理解,测试Tag(否则假设NavigableString)然后可以生成DataFrame 的行。然后,您可以根据目标列和 ASN 使用 pandas 过滤和子集 DataFrame

      import requests
      from bs4 import BeautifulSoup, Tag
      import pandas as pd
      
      asn = 'AS 1031'
      
      r = requests.get('http://bgpstream.com/')
      soup = BeautifulSoup(r.text, 'lxml')
      headers = [th.text for th in soup.select('#all_events th')]
      
      df = pd.DataFrame([[td.get_text(' ').replace('\n','') if isinstance(td, Tag) else td for td in tr] for tr in soup.select('#all_events tr:has(td:nth-child(1):-soup-contains("Hijack"))')])
      
      df2 = df[[1, 5, 7]]
      df2.columns = ['Event type', 'ASN', 'Start time (UTC)']
      
      print(df2[df2['ASN'].str.contains(f'{asn}')])
      

      感谢@Nihilist 声明人们也可以使用 read_html 来抓取表格。然后您可以过滤:

      df2 = pd.read_html('http://bgpstream.com/')[0]
      print(df2[(df2['ASN'].str.contains(f'{asn}')) & (df2['Event type'].str.contains('Hijack'))])
      

      【讨论】:

      • df = pd.read_html('http://bgpstream.com/')[0] 看起来更简单
      • @Nihilist 谢谢。是的,干净多了。
      【解决方案3】:

      如果&lt;td class="event_type"&gt; 包含劫持,您似乎需要每个 tr 标签中的&lt;td class="asn"&gt;

      使用列表理解

      trs = soup.find_all("tr")
      tds_with_asn = [tr.find_all("td", class_="asn") for tr in trs if "Hijack" in tr.find("td", class_="event_type").text]
      tds_with_your_asn = [i.text for i in tds_with_asn if "47725" in i.text]
      

      使用 Pandas 的另一种方法

      import pandas as pd
      
      # Define ASN here
      asn = 47725
      
      df = pd.read_html('http://bgpstream.com/')[0]
      df_filt = df.loc[(df['Event type'].str.contains("Hijack")) & (df['ASN'].str.contains(f"{asn}"))]
      df_filt.to_csv('output.csv', index=False) #this will export final data to csv
      

      【讨论】:

        猜你喜欢
        • 2016-07-18
        • 1970-01-01
        • 2018-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多