質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

0回答

681閲覧

reモジュールを用いて正規表現に適合した要素を抽出した際に、抽出した行と列を参考に他の要素を抽出したい

gran-1123

総合スコア18

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/02/07 07:53

編集2022/01/12 10:55

前提・実現したいこと

現在、「機動戦士ガンダム」シリーズに関するWebページのHTMLを一つにまとめたデータを入力として、BeautifulSoupでテキスト部分のみを抽出。それで抽出したテキストから「作中の年代」「作中の出来事」「作品名」の三つの要素に適合するテキストを正規表現を用いて抽出し、リストとして出力するプログラムを作成しています。

リストが出力される前の処理として、「作中の年代」に適合するテキストが抽出された行を参照して、「作中の出来事」「作品名」に適合するテキストをその行、あるいはその行に最も近い別の行から抽出して単純に抽出された順番でリストに格納、そのリスト内の重複を排除する処理を施し、重複が排除されたリストを出力したいと考えています。

また、3つ全ての要素が揃っていない場合は考えなくてよいものとしています。

発生している問題・エラーメッセージ

「作中の年代」を抽出し、年代順にソートすることと、重複を排除する処理はできたのですが、finditerの返り値をどのように使えれば「作中の出来事」「作品名」を抽出する場所を「作中の年代」が抽出された行、あるいはその前後の行に限定できるのかができるかわからずに途方にくれてしまいました。

該当のソースコード

python3

1#coding:utf-8 2import re 3from bs4 import BeautifulSoup 4import pandas as pd 5 6results_hi = []#年号を格納しておく関数 7results_t = []#作品タイトルを格納しておく関数 8results_ha = []#出来事を格納しておく関数 9count_line = 0 10 11absobe_pattern_history = 'U.C.[0-9]{4}|宇宙世紀[0-9]{4}'#宇宙世紀の年号 12absobe_pattern_title = '機動戦士ガンダム[  \t\n\r\f\v一-龥ぁ-んァ-ンa-zA-ZΖ0-9_ー・.]{1,}|機動戦士ガンダム|機動戦士[\t\n\r\f\v一-龥ぁ-んァ-ンa-zA-ZΖ0-9_ー・.]{1,}ガンダム|機動戦士[\t\n\r\f\v一-龥ぁ-んァ-ンa-zA-ZΖ0-9_ー・.]{1,}ガンダム[  \t\n\r\f\v一-龥ァ-ンa-xA-ZΖ0-9_ー・]{1,}|ガンダム・センチネル'#作品タイトル抽出パターン 13absobe_pattern_happen = '[\t\n\r\f\v一-龥ァ-ンa-zA-Z0-9_ー・]{1,}戦争|[\t\n\r\f\v一-龥ァ-ンa-zA-Z0-9_ー・]{1,}戦役|[\t\n\r\f\v一-龥ァ-ンa-zA-Z0-9_ー・]{1,}紛争|[\t\n\r\f\v一-龥ァ-ンa-zA-Z0-9_ー・]{1,}抗争|[\t\n\r\f\v一-龥ァ-ンのa-zA-Z0-9_ー・]{1,}事件|[\t\n\r\f\v一-龥ァ-ンのa-zA-Z0-9_ー・]{1,}反乱'#出来事抽出パターン 14 15# encoding は取得したページの文字コードを選択 16filepath = '/home/urai/crawling/gandamu/gandamu uchuuseiki/26.html' 17with open(filepath , encoding='utf-8') as f: 18 html = f.readlines()#入力データの各行を要素としたリストを取得 19 for i in html: 20 soup = BeautifulSoup(i, 'html.parser')#Soupでhtmlからデータを取る 21 for text in soup.find_all(text=True):#テキストのみを抽出 22 text.strip()#空白、改行を排除 23 count_line += 1#行数をカウント 24 matchedList_h = re.finditer(absobe_pattern_history,text)#条件に適合した文(年号)をイテレータとして返す 25 if matchedList_h:#もし適合していたら 26 for hi in matchedList_h: 27 results_hi.append(hi.group())#マッチした文字列をresults_hiに格納 28 matchedList_ha = re.findall(absobe_pattern_happen,text)#条件に適合した文(年号)を抽出、matchedList_haに格納、どうやってmatchedList_hが判定した行の付近から抽出させる? 29 matchedList_t = re.findall(absobe_pattern_title,text)#条件に適合した文(年号)を抽出、matchedList_tに格納、どうやってmatchedList_hが判定した行の付近から抽出させる? 30 results_ha.append(matchedList_ha)#esults_haに格納 31 results_t.append(matchedList_t)#results_tに格納 32 f.close() 33 34 UC_title = [t[0] for t in results_t if t != []]#リスト内の空のリストを消して入れ子構造を解消 35 UC_happen = [ha[0] for ha in results_ha if ha != []]#上に同じ 36 37 UCH = ",".join(results_hi)#置き換え処理のために一度リストを一つの文字列にする 38 UC_history2 = re.sub(r'宇宙世紀([0-9]{4})', r'U.C.\1',UCH)#re.subで"宇宙世紀"の部分を"U.C."に置き換え 39 UCH2 = UC_history2.split(",")#リストに戻す、これで表記を統一 40 41 UCHA = [i for i in UC_happen if not re.search('.*画像.*', i) and not re.search('.*Blu.*', i)\ 42 and not re.search('.*内容.*', i) and not re.search('.*DVD.*', i) and not re.search('.*BOX.*', i)\ 43 and not re.search('.*ボックス*', i) and not re.search('.*コミック*', i) and not re.search('.*公式*', i)\ 44 and not re.search('.*作画*', i) and not re.search('.*シリーズ*', i)]#「作中の出来事」を内包したリストからノイズとなる単語を含んだ要素の排除したリストの生成 45 46 UCT = [i for i in UC_title if not re.search('.*画像.*', i) and not re.search('.*Blu.*', i)\ 47 and not re.search('.*内容.*', i) and not re.search('.*DVD.*', i) and not re.search('.*BOX.*', i)\ 48 and not re.search('.*ボックス*', i) and not re.search('.*コミック*', i) and not re.search('.*公式*', i)\ 49 and not re.search('.*作画*', i) and not re.search('.*シリーズ*', i) and not re.search('.*図鑑*', i)\ 50 and not re.search('.*年表*', i) and not re.search('.*時系列*', i) and not re.search('.*ガンプラ*', i)\ 51 and not re.search('.*設定*', i)and not re.search('.*ナラティブ*', i)and not re.search('.*辞典*', i)\ 52 and not re.search('.*全集*', i)and not re.search('.*記録*', i)and not re.search('.*アニメ*', i)]#「作品名」を内包したリストからノイズとなる単語を含んだ要素の排除したリストの生成 53 54 his_list = sorted(set(UCH2), key=UCH2.index)#sortedでリスト内部の重複を排除 55 tit_list = sorted(set(UCT), key=UCT.index)#上に同じ 56 hap_list = sorted(set(UCHA), key=UCHA.index)#上に同じ 57 58 his_list.sort()#his_listの中身を古い>新しいの順番に並び替える 59 60 print(his_list) 61 print(hap_list) 62 print(tit_list) 63 64出力(リストの中身) 65his_list:['U.C.0001', 'U.C.0058', 'U.C.0063', 'U.C.0068', 'U.C.0071', 'U.C.0074', 'U.C.0077', 'U.C.0078', 'U.C.0079', 'U.C.0080', 'U.C.0081', 'U.C.0082', 'U.C.0083', 'U.C.0084', 'U.C.0085', 'U.C.0087', 'U.C.0088', 'U.C.0089', 'U.C.0090', 'U.C.0091', 'U.C.0092', 'U.C.0093', 'U.C.0094', 'U.C.0095', 'U.C.0096', 'U.C.0097', 'U.C.0099', 'U.C.0100', 'U.C.0103', 'U.C.0104', 'U.C.0105', 'U.C.0106', 'U.C.0107', 'U.C.0120', 'U.C.0121', 'U.C.0122', 'U.C.0123', 'U.C.0133', 'U.C.0136', 'U.C.0140', 'U.C.0143', 'U.C.0149', 'U.C.0153', 'U.C.0168', 'U.C.0169', 'U.C.0203', 'U.C.0218', 'U.C.0223', 'U.C.0653', 'U.C.1000'] 66 67hap_list:['第二次オールズモビル戦役', '一年戦争', 'ラプラス事件', 'のラプラス事件', 'デラーズ紛争', 'グリプス戦役', 'ペズンの反乱', '第一次ネオ・ジオン抗争', '第二次ネオ・ジオン抗争', 'ラプラス戦争', 'マフティー戦争', '第一次オールズモビル戦役', 'シャアの反乱', 'ゼブラゾーン事件', 'コスモ・バビロニア建国戦争', '木星戦役', 'ザンスカール戦争', 'ガイアの光事件', '独立戦争', '30バンチ事件', 'オールズモビル戦役', '年戦争', '第一次ネオ・ジオン戦争', '1年戦争'] 68 69tit_list:['機動戦士ガンダム', '機動戦士ガンダム 逆襲のシャア', '機動戦士ガンダムF91', '機動戦士ガンダム U.C.0094 アクロス・ザ・スカイ', '機動戦士ガンダム U.C.0096 ラスト・サン', '機動戦士ユニコーンガンダム', '機動戦士Vガンダム', '機動戦士クロスボーン・ガンダム', '機動戦士ガンダムUC', '機動戦士ガンダム THE ORIGIN', '機動戦士ガンダム0083', '機動戦士Zガンダム', '機動戦士ガンダムZZ', '機動戦士ガンダムF90', '機動戦士ガンダム THE ORIGIN VI 誕生 赤い彗星 ', 'ガンダム・センチネル', '機動戦士ガンダムNT ', '機動戦士ガンダム 閃光のハサウェイ', '機動戦士ガンダムF90 ', '機動戦士ガンダム\u3000シルエットフォーミュラ91 機動戦士ガンダム シルエットフォーミュラ91 ', '機動戦士ガンダムF91 クロスボーン・バンガード', '機動戦士ガンダムサンダーボルト', '機動戦士ZZガンダム', '機動戦士ムーンガンダム', '機動戦士ガンダムNT', '機動戦士ガンダムUC ', '機動戦士ガンダム サンダーボルト DECEMBER SKY ', '機動戦士Ζガンダム', '機動戦士ガンダム 逆襲のシャア ', '機動戦士ガンダム閃光のハサウェイ', '機動戦士ガンダムF91 ']

試したこと

if len(matchedList_h):を用いて年代の要素が抽出された回数だけ他の要素の抽出を実行する処理を試そうとしたり、findallをre.searchに変えたりしましたが、思うようにいきませんでした。

その他には、何かに使えるかという考えで、今何行目を読み込んでるのかを確認するcount_lineを追加し、マッチしたテキストの抽出方法をfindallからfinditerに変更しました。

補足情報(FW/ツールのバージョンなど)

Pythonのバージョンは3.6.5です。

入力データである'/home/urai/crawling/gandamu/gandamu uchuuseiki/26.html'の中身は「機動戦士ガンダム」内の歴史である「宇宙世紀」について記された複数のWebページのHTMLデータを一つにまとめた物になります。(「ガンダム 宇宙世紀」とグーグル検索して出てきた上位25ページのHTMLをまとめている)
抽出の際にはHTMLに記載されたテキストは一行ずつ読み取られ、文字列となります。

事前の実験の結果、各要素に該当するテキストの数は均一ではありません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2019/02/07 09:10

全体的に何がしたくて何が問題なのかが把握できません。 第三者が検証できるようなデータをもとに、抽出?処理、やりたいことを単純化して提示したほうが回答得られやすいと思います。
wwbQzhMkhhgEmhU

2019/02/07 18:52

確かにいろいろ不明点もありますが、探している文字列が見つかった場所まで欲しいなら、findallではなくてfinditerの方がいいと思いますよ。
wwbQzhMkhhgEmhU

2019/02/08 06:10

すでに最初に書いていた何行目の何文字目までは分かるはずです。 具体的にどんな文面から抽出しているかも、聞かれているのに書かれていません。 あなたがやりたいことが分からないのに、これをやってもできないあれをやってもできない、ではどうしようもありません。 まずはやりたいことを明確にしましょう。多分不明点は、 ・1行にはどんな文面が記述されているのか?複数文?自然言語?CSVのような形式が決まったもの? ・最終的に年表と言っているということは、これらは年号・タイトル・出来事がセットになっているのではないか? ・年号・タイトル・出来事の順序性・出現可能性は? ・同一年号に複数のタイトルや出来事が入っている場合はどうするのか? ・単一の行にそれらがあった場合はどうするのか? ・年表なので年号順に並べたいのかそうでないのか? etc 技術的に不明な部分が正規表現の一致部分が何文字目なのかを知ることだけなのであれば、あとはもう自分で実装できるはずですが、それ以上のことが分からないのであれば、きちんとそれらを説明してから質問しましょう(上記だけでも十分ではありません)。
wwbQzhMkhhgEmhU

2019/02/08 07:10

全く不明確で、回答になっていませんよ。 あとはもう自分でやってください。添削会場ではないので。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問