[Python][Scraping]PythonでのスクレイピングとCSVファイルへ書き込み

multicolored soccer ball on green field python
Photo by Pixabay on Pexels.com

データの抽出

いつものBeautifulSoupで。ほとんどpowered by ChatGPTであるが、一部文字化け部分についてはChatGPTは解決できなかったので、加筆している。

必要ライブラリのimport

こちらで必要ライブラリをimportしておく。

import pandas as pd
import numpy as np

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

htmlのパーシング

まとまった情報であれば何でもいいので、J-Leagueの試合結果を例にする。試合結果はこちらのurlから取得できる。

このままcsvに貼り付けても良さそうだけど。

このアドレスのcompetitionの部分をいじれば各年ごとの試合結果を取得できそう。例えば、2000年の日本で行われた全試合結果を取得してみる。ここで、後で詳しくみるが、まず最初にencodingを指定しておくことが重要。

# Parsing HTML with BeautifulSoup
response = requests.get("https://data.j-league.or.jp/SFMS01/search?competition_years=2000")
response.encoding = "utf-8"
bs = BeautifulSoup(response.text, "html.parser")

ヘッダーの取得

後でデータが何か忘れないように、ヘッダーも取得しておく。

# Get table header
headers = []
for th in bs.find("thead").find_all("th"):
    headers.append(th.text.strip())

データの取得

これも簡単

# Get data from table
data = []
for tr in bs.find("tbody").find_all("tr"):
    row = []
    for td in tr.find_all("td"):
        row.append(td.text.strip())
    data.append(row)

CSVファイルへの書き出し

ここが一番大変だった。何が大変かというと、encodingを”shift-jis”にすると、出てくるCSVファイルがどうしても文字化けしてしまう。そこで、下記のように一度”utf-8″でencodingしつつ、それ以外の文字コードを無視、さらに”utf-8″で再度decodingというややわかりにくい手法を行なっている。

# Write to CSV file
with open("/Users/YourDirectory/Documents/j-league.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    # Convert headers to utf-8 encoding
    headers_encoded = [h.encode('utf-8', 'ignore').decode('utf-8') for h in headers]
    writer.writerow(headers_encoded)
    # Convert data to utf-8 encoding
    data_encoded = [[d.encode('utf-8', 'ignore').decode('utf-8') for d in row] for row in data]
    writer.writerows(data_encoded)

無事にCSVファイルが完成・・・?

ところがこれでも出てきたCSVファイルを見ると、しっかり文字化けしている。

なかなか見事な文字化け。

文字化けの解決方法

これを解決するには、まずcsvファイルをMacのテキストエディットで開く。

Macの”テキストエディット”で開くとencodingの問題は解消する。

これをメニューの「ファイル」→「複製」して、複製したものの名前を.csvにしてから、「標準テキストのエンコーディング」で「日本語(Shift JIS X0213)」を指定すればOK。

これで無事文字化けのないCSVファイルが得られる。

forループで1993年から2023年まで一気に

複数年度に渡って情報を抽出する場合、以下のようにすればいい。ほとんどcodeは一緒なので、一気に掲載。

for year in range(1993, 2023):
    # Parsing HTML with BeautifulSoup
    response = requests.get("https://data.j-league.or.jp/SFMS01/search?competition_years={0}".format(year))
    response.encoding = "utf-8"
    bs = BeautifulSoup(response.text, "html.parser")

    # Get table header
    headers = []
    for th in bs.find("thead").find_all("th"):
        headers.append(th.text.strip())

    # Get data from table
    data = []
    for tr in bs.find("tbody").find_all("tr"):
        row = []
        for td in tr.find_all("td"):
            row.append(td.text.strip())
        data.append(row)

    # Write to CSV file
    with open("/Users/YourDirectory/Documents/j-league{0}.csv".format(year), "w", encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        # Convert headers to utf-8 encoding
        headers_encoded = [h.encode('utf-8', 'ignore').decode('utf-8') for h in headers]
        writer.writerow(headers_encoded)
        # Convert data to utf-8 encoding
        data_encoded = [[d.encode('utf-8', 'ignore').decode('utf-8') for d in row] for row in data]
        writer.writerows(data_encoded)

このcodeを実行すると、j-league1994.csvからj-league2023.csvまで複数のCSVファイルが一気に出てくる。後はこれを以下のコードで結合すれば良い。

#merge all CSV
import glob
csv_files = glob.glob("*.csv")
list = []
for file in csv_files:
    list.append(pd.read_csv(file))
df = pd.concat(list)
df.to_csv("merged.csv", index = False)

出てくるCSVファイルもやはり文字化けしているが、上記の要領でテキストエディットを用いて再度変換すればOK。

pandasでの読み込み

といろいろやってみても、実はpandasで読み込むときは変な変換をしないで、そのままのCSVファイルの方でないと、逆に文字化けしてしまっていることもある。ここらへんは、個々の環境と状況に応じて使い分けを。

関連記事

PythonによるWebスクレイピング
JSONファイルの読み込みについて

コメント

タイトルとURLをコピーしました