Closed5

fandom-pyのメモ

kun432kun432

Haystackのチュートリアルで「ゲーム・オブ・スローンズ」のあらすじがよく使われていて、どうやらwikipediaとかではなくてファンが作ったwikiから情報を持ってきている様子。

wikipediaはカバーするトピックの幅は広いんだけど、例えば全エピソードのあらすじ、みたいな詳細な情報までは書かれていない。RAGのテストでは

  • 特定のトピック
  • ボリュームがある
  • 詳細までカバーされている

と使いやすいので、こういうファンメイドなものが使われるのは納得感ある(チュートリアル的にも親しみやすいだろうし)。

調べてみたら海外にはfandomという個々のトピックのファンによるwikiがあるらしい。

https://www.fandom.com/

ためしに昔ハマっていた海外ドラマ「フレンズ」のトピックを見てみると、このテーマだけで1586記事もあるらしく、全エピソードの詳細なあらすじとかまで記載されていた。

https://friends.fandom.com/wiki/Friends_Wiki

ただwikipediaと違ってデータセットとして利用できるようにはなっていないらしく、スクレイプするしかないかなーと思ってたら、非公式なpythonライブラリがあった。

https://github.com/NikolajDanger/fandom-py

開発止まってるっぽいけど、とりあえず試してみた。

kun432kun432

インストール

!pip install fandom-py

最初にwiki空間を設定。wiki空間は多分https://◯◯◯.fandom.com/のところ。今回は「フレンズ」のものを使うので、https://friends.fandom.com/から"friends"になる。

import fandom

fandom.set_wiki("friends")

特定のページを取得する

season_1 = fandom.page("Season 1")

以下のようなプロパティが定義されている。

dir(season_1)
['_FandomPage__continued_query',
 '_FandomPage__load',
 '_FandomPage__title_query_param',
 '__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'content',
 'html',
 'images',
 'language',
 'pageid',
 'plain_text',
 'revision_id',
 'section',
 'sections',
 'summary',
 'title',
 'url',
 'wiki']

実際に使うにはcontentを使うと良い。contentを使うとページの構造が取得できる。

from pprint import pprint

pprint(season_1.content)
{'content': 'Season 1 of Friends aired from September 22, 1994 to May 18, 1995 '
            'on NBC in the US.',
 'infobox': 'Season\n'
            'Season 1\n'
            'Season\n'
            '1\n'
            'Episodes\n'
            '23\n'
            'Aired from\n'
            'September 22, 1994 - May 18, 1995\n'
            'Premiere\n'
            'The Pilot\n'
            'Finale\n'
            'The One Where Rachel Finds Out\n'
            'Other seasons\n'
            '← Previous\n'
            'Next →\n'
            '–\n'
            '"Season 2"',
 'sections': [{'content': 'This season introduced the six main characters: '
                          'Chandler Bing, Phoebe Buffay, Monica Geller, Ross '
                          'Geller, Rachel Greene, and Joey Tribbiani.\n'
                          'Rachel, who left her fiancé at the altar on her '
                          'wedding day, has come to New York and ends up '
                          'living with Monica as her roommate when Phoebe had '
                          'just moved out. It establishes early on in the '
                          'season that Ross has been infatuated with Rachel '
                          'since the two characters attended high school. '
                          'Several episodes revolve around his attempts to '
                          'tell her how he feels. Ross leaves for a fossil dig '
                          'in China at the end of the season, missing out on '
                          "Rachel's birthday party but staying long enough to "
                          'give her a meaningful present: a cameo that was '
                          "just like the one that belonged to Rachel's "
                          'grandmother. Chandler accidentally reveals that '
                          'Ross is in love with Rachel, much to her shock. '
                          'Rachel realizes that she has feelings for Ross and '
                          'rushes off to the airport to tell him that she '
                          'wants to pursue a relationship with him. As she '
                          'waits at the gate for Ross to arrive, the season '
                          'ends on a cliffhanger as he gets off the plane but '
                          'with a new girlfriend: Julie.\n'
                          "Ross' estranged lesbian wife, Carol Willick, is "
                          "pregnant with his baby. This puts him and Carol's "
                          'lesbian life partner, Susan Bunch, in an awkward '
                          'position. When the baby is born at the end of the '
                          'season, Ross, Carol, and Susan agree to name him '
                          "Ben: after a name tag on a janitor's uniform worn "
                          'by Phoebe.\n'
                          'The episodic nature of the season sees the other '
                          'characters having multiple dates, many of which go '
                          'wrong (Monica dates a minor in one episode). The '
                          'recurring character of Janice is introduced as a '
                          'girlfriend Chandler breaks up with in an early '
                          'episode but frequently returns to through the '
                          'ensuing ten seasons.',
               'title': 'Season summary'},
              {'content': 'Jennifer Aniston as Rachel Greene\n'
                          'Courteney Cox as Monica Geller\n'
                          'Lisa Kudrow as Phoebe Buffay/Ursula Buffay ("The '
                          'One With Two Parts, Part 1"/"The One With Two '
                          'Parts, Part 2")\n'
                          'Matt LeBlanc as Joey Tribbiani\n'
                          'Matthew Perry as Chandler Bing\n'
                          'David Schwimmer as Ross Geller/Russ',
               'sections': [{'content': 'Anita Barone as Carol Willick ("The '
                                        'One With The Sonogram At The End")\n'
                                        'Jane Sibbett as Carol Willick\n'
                                        'Maggie Wheeler as Janice\n'
                                        'Mitchell Whitfield as Barry Farber\n'
                                        'Cosimo Fusco as Paolo\n'
                                        'Jessica Hecht as Susan Bunch\n'
                                        ' \n'
                                        ' ',
                             'title': 'Recurring Cast'}],
               'title': 'Starring'},

ただ完全には対応できてないようで、ページの作りによってはうまくパースできなくてコケたりする。この辺を都度ソースを修正すればまあ使えなくもない。

kun432kun432

雑にシーズン1〜シーズン10の全エピソードを1エピソードごとにmarkdownに変換してファイルに出力してみた。ちょいちょいイレギュラーな感じでコケるので、ライブラリ修正以外に、アドホックに処理してりもしてて、「フレンズ」以外のケースでの再利用性は皆無。

import pandas as pd
import fandom
import re
from tqdm.notebook import tqdm

df = pd.DataFrame(columns=["season", "#", "total#", "title", "writer", "director", "airdate", "short plot"])

def object_to_markdown(data, depth=1):
    markdown = []

    # title
    markdown.append(f"{'#' * depth} {data['title']}\n")
    
    # content
    markdown.append(f"{data['content']}\n")
    
    # sections
    for section in data.get('sections', []):
        if section['title'] not in ['External links', 'Episode Navigation', 'Photos']:
            markdown.append(object_to_markdown(section, depth + 1))
    
    return "\n".join(markdown)

fandom.set_wiki("friends")

regexp_eps_no = r'^([0-9]{1,2}|-)$'

for season in range(1,11):
    episode_list = fandom.page(f"Season_{season}")
    eps = episode_list.content["sections"][-1]["content"].split("\n")[7:]
    i = 0
    while i < len(eps):
        if re.fullmatch(regexp_eps_no, eps[i]) and re.fullmatch(regexp_eps_no, eps[i+7]):
            chunk = eps[i:i+7]
            df.loc[len(df)] = [season] + chunk
            i += 7
        elif re.fullmatch(regexp_eps_no, eps[i]) and not re.fullmatch(regexp_eps_no, eps[i+7]):
            chunk = eps[i:i+8]
            chunk[-2:] = ["".join(chunk[-2:])]
            df.loc[len(df)] = [season] + chunk
            i += 8
        else:
            i += 7

df = df[df["#"] != "-"]

for index, row in tqdm(df.iterrows(), total=df.shape[0]):
    epnum = str(row["total#"]).zfill(3)
    title = row["title"].replace('"', '')
    f_title = title.replace(" ","_")
    path = f"data/{epnum}_{f_title}.txt"

    p = fandom.page(title)
       
    with open(path, mode="w") as f:
        f.write(object_to_markdown(p.content))
kun432kun432

国内だとこの辺がクリアになってるものがあまりないイメージ。

このスクラップは2023/10/05にクローズされました