Pythonでスクレイピング方法について


pythonで以下のページをスクレイピングし、フライト情報を取得したいです。

[https://www.fukuoka-
airport.jp/flight/?depArv=D&domCode=all&domLocation=all&domNum=&domTime=all&intCode=all&intDepArv=D&intDom=D&intLocation=all](https://www.fukuoka-
airport.jp/flight/?depArv=D&domCode=all&domLocation=all&domNum=&domTime=all&intCode=all&intDepArv=D&intDom=D&intLocation=all)

selenium・BeautifulSoupを用いてコードを書いたのですが、  
該当ページの文字を抽出できず、困っている状況です。

すいません、コードのどこがいけないのかスクレイピングに詳しい方教えていただけませんでしょうか。

HTML

[code]

    <div class="flight-result departure"><div class="h-flight"><ul><li class="h-txt01">出発時刻</li><li class="h-txt02">行先・便名</li><li class="h-txt03"><span>チェックイン<br>カウンター</span><span>検査場</span><span>ゲート</span></li><li class="h-txt04">状況</li></ul></div><ul><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-ANA-0244"><div class="flight-time"><span class="flight-time-init"><span>09:00</span></span><span class="flight-changetime">09:16</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_NH.jpg" alt=""></div><div><p class="flight-destination">東京</p><p class="flight-code">ANA244</p></div></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="north">北</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>8</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-ANA-0422"><div class="flight-time"><span class="flight-time-init"><span>09:00</span></span><span class="flight-changetime">08:56</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_NH.jpg" alt=""></div><div><p class="flight-destination">大阪</p><p class="flight-code">ANA422</p></div></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="north">北</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>6</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-JAL-3581"><div class="flight-time"><span class="flight-time-init"><span>09:00</span></span><span class="flight-changetime">08:53</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_JL.jpg" alt=""></div><div><p class="flight-destination">高知</p><p class="flight-code">JAL3581</p></div></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="south">南</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>11</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-FDA-0302"><div class="flight-time"><span class="flight-time-init"><span>09:05</span></span><span class="flight-changetime">09:03</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_FH.jpg" alt=""></div><div><p class="flight-destination">名古屋/小牧</p><p class="flight-code">FDA302</p></div></div><div class="flight-codeshare"><ul><li><span class="flight-logo"><img src="/uploads/2020/07/img_flight_JL.jpg" alt=""></span><span class="flight-code">JAL4402</span></li></ul></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="north">北</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>3</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-JAL-0306"><div class="flight-time"><span><span>09:05</span></span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_JL.jpg" alt=""></div><div><p class="flight-destination">東京</p><p class="flight-code">JAL306</p></div></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="south">南</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>10</span></div></div><div class="flight-status">欠航</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-SFJ-0042"><div class="flight-time"><span class="flight-time-init"><span>09:10</span></span><span class="flight-changetime">09:07</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/12a917db8ed1f43045e51332c95d038b737d24e7.jpg" alt=""></div><div><p class="flight-destination">東京</p><p class="flight-code">SFJ42</p></div></div><div class="flight-codeshare"><ul><li><span class="flight-logo"><img src="/uploads/2020/07/img_flight_NH.jpg" alt=""></span><span class="flight-code">ANA3842</span></li></ul></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="south">南</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>10</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-JTA-0053"><div class="flight-time"><span class="flight-time-init"><span>09:25</span></span><span class="flight-changetime">09:20</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_NU.jpg" alt=""></div><div><p class="flight-destination">沖縄/那覇</p><p class="flight-code">JTA53</p></div></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="south">南</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>12</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-ORC-0097"><div class="flight-time"><span><span>09:35</span></span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_OC.jpg" alt=""></div><div><p class="flight-destination">福江</p><p class="flight-code">ORC97</p></div></div><div class="flight-codeshare"><ul><li><span class="flight-logo"><img src="/uploads/2020/07/img_flight_NH.jpg" alt=""></span><span class="flight-code">ANA4697</span></li></ul></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="south">南</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>82</span></div></div><div class="flight-status">欠航</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-ANA-1076"><div class="flight-time"><span class="flight-time-init"><span>09:40</span></span><span class="flight-changetime">09:35</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_NH.jpg" alt=""></div><div><p class="flight-destination">東京</p><p class="flight-code">ANA1076</p></div></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="north">北</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>7</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-ANA-1203"><div class="flight-time"><span class="flight-time-init"><span>09:40</span></span><span class="flight-changetime">09:39</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_NH.jpg" alt=""></div><div><p class="flight-destination">沖縄/那覇</p><p class="flight-code">ANA1203</p></div></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="south">南</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>11</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-FDA-0142"><div class="flight-time"><span class="flight-time-init"><span>09:50</span></span><span class="flight-changetime">09:45</span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_FH.jpg" alt=""></div><div><p class="flight-destination">静岡</p><p class="flight-code">FDA142</p></div></div><div class="flight-codeshare"><ul><li><span class="flight-logo"><img src="/uploads/2020/07/img_flight_JL.jpg" alt=""></span><span class="flight-code">JAL3811</span></li></ul></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="north">北</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>5</span></div></div><div class="flight-status">出発済み</div></a></li><li><a href="/flight/detail.html?id=FUK-2022-05-12-2022-05-12-D-ORC-0065"><div class="flight-time"><span><span>09:50</span></span></div><div class="flight-main"><div class="flight-ttl"><div class="flight-logo"><img src="/uploads/2020/07/img_flight_OC.jpg" alt=""></div><div><p class="flight-destination">宮崎</p><p class="flight-code">ORC65</p></div></div><div class="flight-codeshare"><ul><li><span class="flight-logo"><img src="/uploads/2020/07/img_flight_NH.jpg" alt=""></span><span class="flight-code">ANA4665</span></li></ul></div></div><div class="flight-place"><div class="flight-map"><span class="txt-sp">チェックイン<br>カウンター</span><span class="icon-map">MAP</span></div><div class="flight-terminal"><span class="txt-sp">検査場</span><span class="south">南</span></div><div class="flight-gate"><span class="txt-sp">ゲート</span><span>82</span>....
    
[/code]

全体のコード

[code]

    import pandas as pd
    import time
    from datetime import datetime as dt, date, timedelta
    from dateutil.relativedelta import relativedelta
    from selenium import webdriver
    from bs4 import BeautifulSoup
    from webdriver_manager.chrome import ChromeDriverManager
    from dateutil.relativedelta import relativedelta
    
    today= dt.now().strftime("%Y%m%d")
    
    yesterday =dt.strftime( dt.today() - relativedelta( days = 1 ), "%Y%m%d" )
    
    #保存ファイル指定
    file="test"+today+".csv"
    
    #url指定
    url = 'https://www.fukuoka-airport.jp/flight/?depArv=D&domCode=all&domLocation=all&domNum=&domTime=all&intCode=all&intDepArv=D&intDom=D&intLocation=all'
    
    driver = webdriver.Chrome(executable_path=ChromeDriverManager().install())
    #driver = webdriver.Chrome(executable_path="C:\selenium\chromedriver.exe")
    
    #フライ情報のサイトを開く
    driver.get(url)
    
    #5秒待機
    time.sleep(5)
    #BeautifulSoup指定
    html = driver.page_source.encode('utf-8')
    soup = BeautifulSoup(html, 'html.parser')
    
    tbl = []
    for li in soup.select('div.flight-result departure ul li'):
    
        data = {}
    
        # 定刻[変更]
        ft = li.select_one('span.flight-time-init')
        if ft is None: continue
        data['定刻[変更]'] = ft.text
        ct = li.select_one('span.flight-changetime')
        if ct: data['定刻[変更]'] += f'\n{ct.text}'
        
        # 出発地[経由]
        st = li.select_one('p.flight-destination')
        data['出発地[経由]'] = st.text if st else ''
        
        #便名
        fn = li.select_one('p.flight-code')
        data['便名'] = fn.text if fn else ''
    
        # 航空会社(コードシェア)
        fa = li.select_one('div.flight-codeshare')
        cdshare = ','.join([s.text for s in fa.find_all(class_='flight-code') if s])
        data['航空会社(コードシェア)'] = cdshare if cdshare else ''
    
        # ターミナル
        term = li.select_one('flight-terminal')
        data['ターミナル'] = term.text if term else ''
    
        #ゲート
        model = li.select_one('flight-gate')
        data['ゲート'] = model.text.split(':')[-1].strip() if model else ''
    
        # 現在の状況
        status = li.select_one('flight-status')
        data['現在の状況'] = status.text if status else ''
        
        tbl.append(data)
    
    df = pd.DataFrame(tbl)
    print(df)
    
    # #Excel形式でハルエネ出力-------------------
    # #df.to_excel(file,index=False,encoding='utf-8')
    df.to_csv(file,index=False,encoding="utf_8_sig")
    
    #driver.close()
    
[/code]

現在の結果

[code]

    df = pd.DataFrame(tbl)
    print(df)
    
    Empty DataFrame
    Columns: []
    Index: []
    
[/code]

お手数ですが、よろしくお願い致します。




3点あって、以下の最初の点がデータを取れない原因です。

指定したいクラス名に空白が入っている時は、そのまま空白を指定するのではなく`.`に置き換える必要があるみたいですね。

[code]

    for li in soup.select('div.flight-result departure ul li'):
    
[/code]

`flight-result departure`を`flight-result.departure`にする必要があるようです。

[code]

    for li in soup.select('div.flight-result.departure ul li'):
    
[/code]

**追記**  
@oriri さんの補足(注意?)記事が追加されたので：

上記を書いたのは開発者ツールで該当タグのCSS Selectorを取得した時に以下のように表示されたためです。

[code]

    #flight-search-area > div > div.flight-result.departure
    
[/code]

ただ、今調べたらこんな記事もあるので、そうそう変なやり方でもなさそうです。  
[BeautifulSoup and class with
spaces](https://stackoverflow.com/q/46718366/9014308)

* * *

上記が通るようになると、今度はコードシェア便情報で問題が出てきます。  
以前の質問と違って、こちらのページではコードシェア便が無い時は`div.flight-codeshare`そのものが存在しないようです。

[code]

    cdshare = ','.join([s.text for s in fa.find_all(class_='flight-code') if s])
    
[/code]

そうすると上記行でエラーになるので、以下のように変更する必要があるようです。

[code]

    cdshare = ','.join([s.text for s in fa.find_all(class_='flight-code') if s]) if fa else ''
    
[/code]

* * *

ターミナル、ゲート、現在の状況については、セレクタの頭に`div.`を付ける必要があるようですね。付けていないと空白のままになります。  
以下変更した該当行を抜粋します。

[code]

        term = li.select_one('div.flight-terminal')
    
        model = li.select_one('div.flight-gate')
    
        status = li.select_one('div.flight-status')
    
[/code]

* * *

**コメント対応**

そもそも質問のソースでは、時刻変更のあった便の情報しか取れていませんでした。  
コードシェア便の情報有無がどうなっているのかと同様に、空港ごとに細かい形式の違いがあるようですね。

ここの部分を：

[code]

        # 定刻[変更]
        ft = li.select_one('span.flight-time-init')
        if ft is None: continue
        data['定刻[変更]'] = ft.text
        ct = li.select_one('span.flight-changetime')
        if ct: data['定刻[変更]'] += f'\n{ct.text}'
    
[/code]

こちらのように変更する必要があります。

[code]

        # 定刻[変更]
        ft = li.select_one('span.flight-time-init')
        if ft is not None:
            data['定刻[変更]'] = ft.text
            ct = li.select_one('span.flight-changetime')
            if ct: data['定刻[変更]'] += f'\n{ct.text}'
        else:
            ft = li.select_one('div.flight-time')
            if ft is None: continue
            data['定刻[変更]'] = ft.text
    
[/code]




3点あって、以下の最初の点がデータを取れない原因です。

指定したいクラス名に空白が入っている時は、そのまま空白を指定するのではなく`.`に置き換える必要があるみたいですね。

[code]

    for li in soup.select('div.flight-result departure ul li'):
    
[/code]

`flight-result departure`を`flight-result.departure`にする必要があるようです。

[code]

    for li in soup.select('div.flight-result.departure ul li'):
    
[/code]

**追記**  
@oriri さんの補足(注意?)記事が追加されたので：

上記を書いたのは開発者ツールで該当タグのCSS Selectorを取得した時に以下のように表示されたためです。

[code]

    #flight-search-area > div > div.flight-result.departure
    
[/code]

ただ、今調べたらこんな記事もあるので、そうそう変なやり方でもなさそうです。  
[BeautifulSoup and class with
spaces](https://stackoverflow.com/q/46718366/9014308)

* * *

上記が通るようになると、今度はコードシェア便情報で問題が出てきます。  
以前の質問と違って、こちらのページではコードシェア便が無い時は`div.flight-codeshare`そのものが存在しないようです。

[code]

    cdshare = ','.join([s.text for s in fa.find_all(class_='flight-code') if s])
    
[/code]

そうすると上記行でエラーになるので、以下のように変更する必要があるようです。

[code]

    cdshare = ','.join([s.text for s in fa.find_all(class_='flight-code') if s]) if fa else ''
    
[/code]

* * *

ターミナル、ゲート、現在の状況については、セレクタの頭に`div.`を付ける必要があるようですね。付けていないと空白のままになります。  
以下変更した該当行を抜粋します。

[code]

        term = li.select_one('div.flight-terminal')
    
        model = li.select_one('div.flight-gate')
    
        status = li.select_one('div.flight-status')
    
[/code]

* * *

**コメント対応**

そもそも質問のソースでは、時刻変更のあった便の情報しか取れていませんでした。  
コードシェア便の情報有無がどうなっているのかと同様に、空港ごとに細かい形式の違いがあるようですね。

ここの部分を：

[code]

        # 定刻[変更]
        ft = li.select_one('span.flight-time-init')
        if ft is None: continue
        data['定刻[変更]'] = ft.text
        ct = li.select_one('span.flight-changetime')
        if ct: data['定刻[変更]'] += f'\n{ct.text}'
    
[/code]

こちらのように変更する必要があります。

[code]

        # 定刻[変更]
        ft = li.select_one('span.flight-time-init')
        if ft is not None:
            data['定刻[変更]'] = ft.text
            ct = li.select_one('span.flight-changetime')
            if ct: data['定刻[変更]'] += f'\n{ct.text}'
        else:
            ft = li.select_one('div.flight-time')
            if ft is None: continue
            data['定刻[変更]'] = ft.text
    
[/code]

