【Python】bs4で指定要素とその値と、直後の要素とその値をpandasデータフレームにする。スクレイピングの備忘録【BeautifulSoup4】 | ムノログ 合同会社ムジンケイカクプロのITノウハウブログ
Pythonと機械学習

【Python】bs4で指定要素とその値と、直後の要素とその値をpandasデータフレームにする。スクレイピングの備忘録【BeautifulSoup4】

python Pythonと機械学習

スクレイピングのプログラム的備忘録

from bs4 import BeautifulSoup
import pandas as pd

HTMLのサンプル

html = """
<div class="entry_contents">
    <h1>h1要素です</h1>
    <h2>h1直下のh2要素です</h2>
        <div class="detail_date">3000/11/11</div>
        <span class="category"><a href="https://www.yahoo.co.jp/">スクレイピング</a></span>
    <div class="text_contents">
        <p id="p1">Pタグの1行目</p>
        <img loading="lazy" src="***.png" alt='一枚目の画像'>
        <div id="wrapper" class="content">
        <p id="p2">なんとかかんとかここに書いてある</p>
    </div>
    <h2>h2:ぽんぽこどう本舗はかわいいたぬきが運営するお店だよ</h2>
    <h1>h1要素の2番めです。変則的にh2の下に入れておきます</h1>
        <p id="p3">いや、きつねが化けているんや</p>
        <p id="p4">えー、そうなの?</p>
</div>
"""

内容は気にしないでください。
疲れの極致にて。

リスト内包表記にif文でh1に続く要素がPだったら、タグのテキストだけをリストに追加する。

soup = BeautifulSoup(html, features="lxml")
lists = []
[lists.append(tag.text) for tag in soup.h1.next_elements if tag.name == 'p']
lists

 

select

all_h1 = soup.select('h1')
[<h1>h1要素です</h1>, <h1>h1要素の2番めです。変則的にh2の下に入れておきます</h1>]

指定タグ以降の要素を取得

soup.h2.next_elements
<generator object PageElement.next_elements at 0x0000027437000F90><br />

イテレータが云々カンヌンにて以下。

for x in soup.h2.next_elements:
 print('*'*10)
 print(x)
**********
h1直下のh2要素です
**********


**********
<div class="detail_date">3000/11/11
        <span class="category"><a href="https://www.yahoo.co.jp/">スクレイピング</a></span>
</div>
**********
3000/11/11
        
**********
<span class="category"><a href="https://www.yahoo.co.jp/">スクレイピング</a></span>
**********
<a href="https://www.yahoo.co.jp/">スクレイピング</a>
**********
スクレイピング
**********


**********


**********
<div class="text_contents">
<p id="p1">Pタグの1行目</p>
<img alt="一枚目の画像" loading="lazy" src="***.png"/>
<div class="content" id="wrapper">
<p id="p2">なんとかかんとかここに書いてある</p>
</div>
<h2>h2:ぽんぽこどう本舗はかわいいたぬきが運営するお店だよ</h2>
<h1>h1要素の2番めです。変則的にh2の下に入れておきます</h1>
<p id="p3">いや、きつねが化けているんや</p>
<p id="p4">えー、そうなの?</p>
</div>
**********


**********
<p id="p1">Pタグの1行目</p>
**********
Pタグの1行目
**********


**********
<img alt="一枚目の画像" loading="lazy" src="***.png"/>
**********


**********
<div class="content" id="wrapper">
<p id="p2">なんとかかんとかここに書いてある</p>
</div>
**********


**********
<p id="p2">なんとかかんとかここに書いてある</p>
**********
なんとかかんとかここに書いてある
**********


**********


**********
<h2>h2:ぽんぽこどう本舗はかわいいたぬきが運営するお店だよ</h2>
**********
h2:ぽんぽこどう本舗はかわいいたぬきが運営するお店だよ
**********


**********
<h1>h1要素の2番めです。変則的にh2の下に入れておきます</h1>
**********
h1要素の2番めです。変則的にh2の下に入れておきます
**********


**********
<p id="p3">いや、きつねが化けているんや</p>
**********
いや、きつねが化けているんや
**********


**********
<p id="p4">えー、そうなの?</p>
**********
えー、そうなの?
**********


**********

リスト内包表記とif

[print(tag.text) for tag in soup.h1.next_elements if tag.name == 'p']
Pタグの1行目
なんとかかんとかここに書いてある
いや、きつねが化けているんや
えー、そうなの?
[None, None, None, None]

要素のあるなし判定(属性)

if soup.div.has_attr('class'):
    [print(tag.text) for tag in soup.h1.next_elements if tag.name == 'p']
else:
    print('pass')

Class化

(素人ながら)最終的にどうまとめたかというのがこちらです。

class Tag_Search:
    
    def __init__(self):
        lists = ['test']
    
    def tags_siblings(self):
        
        self.lists = []
        
        soup = self.soup
        tags = soup.find_all(self.tag_target)
        
        if tags is None:
            pass
        else:
            #print(tags)
            for tag in tags:
                
                #print(tag.name,tag.text)

                tag_sib = tag.next_siblings
                
                #print(tag_sib,':sib')
                
                for sibling in tag_sib:
                    #print(type(sibling))
                    if sibling.name == 'p':
                        self.lists.append([tag.text,sibling.text])
                        #print(sibling.name,sibling.text)
        return self.lists

要素のあるなし判定をifでやっておいて、next_siblingsでターゲット要素の直後の要素と値も取得します。

TS = Tag_Search()
TS.soup = BeautifulSoup(html, features="lxml")

for tag in ['h1','h2']:
    TS.tag_target = tag
    TS.tags_siblings()
pd.DataFrame(TS.lists,columns=['h','content'])
p いや、きつねが化けているんや
p えー、そうなの?
p いや、きつねが化けているんや
p えー、そうなの?
h	content
0	h2:ぽんぽこどう本舗はかわいいたぬきが運営するお店だよ	いや、きつねが化けているんや
1	h2:ぽんぽこどう本舗はかわいいたぬきが運営するお店だよ	えー、そうなの?