🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1431閲覧

Pythonでテキストファイルからマッチしたデータを取得したい

fc2LiveAdult

総合スコア4

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/12/28 14:47

編集2020/12/28 14:48

前提・実現したいこと

大学の授業データをスクレイピングしてまとめています。pdfminerで取得して変換した2つのテキストデータのようにぐちゃぐちゃで思ったようにデータを取得できません。取得したいデータは科目の名前、教師の名前、単位数、前期か後期かの4つです。それらを多次元の辞書でまとめる必要があります。

ただしテキストデータのように欲しいデータはぐちゃぐちゃですが、ほしいデータはそれぞれの題目にスペースを1つ挟んだ次の行に必ず存在しています。これを使ってデータを取得しようとしてますが思うようにコードがかけないです。

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

エラーメッセージは発生していません

該当のソースコード

Python

1import sys 2sys.path.append('C:\Python38\lib\site-packages') 3import os 4import shutil 5from os import path 6 7from pdfminer.converter import TextConverter 8from pdfminer.layout import LAParams 9from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager 10from pdfminer.pdfpage import PDFPage 11 12def convert_text(): 13 # textディレクトリ作成、既に存在すれば全削除&再作成 14 this_path = os.getcwd() + '\app\Http\Python\text' 15 exists = os.path.exists(this_path) 16 if (exists == True): 17 shutil.rmtree(this_path) 18 os.mkdir(this_path) 19 else: 20 os.mkdir(this_path) 21 22 # pdfディレクトリのファイル全取得 23 this_path = os.getcwd() + '\app\Http\Python\pdf' 24 files = [] 25 for file in os.listdir(this_path): 26 if os.path.isfile(os.path.join(this_path, file)): # ファイルのみ 27 files.append(file) 28 29 for file in files: 30 # pdfフォルダからファイル取得, 拡張子を.txtに変換 31 this_path = os.getcwd() + '\app\Http\Python\pdf\' 32 input_path = this_path + file 33 this_path = os.getcwd() + '\app\Http\Python\text\' 34 output_path = this_path + file.replace('.pdf', '.txt') 35 36 # コンバート 37 manager = PDFResourceManager() 38 with open(output_path, "wb") as output: 39 with open(input_path, 'rb') as input: 40 with TextConverter(manager, output, codec='utf-8', laparams=LAParams()) as conv: 41 interpreter = PDFPageInterpreter(manager, conv) 42 for page in PDFPage.get_pages(input): 43 interpreter.process_page(page)

Python

1import os 2import glob 3import sys 4 5def get_data(): 6 # テキストファイル取得 7 this_path = os.getcwd() + '\app\Http\Python\text' 8 files = glob.glob(this_path + '\*.txt') 9 10 # データ取得 11 data_list = [] 12 for file in files: 13 with open(file, 'r', encoding="utf-8") as f: 14 line = f.readlines() 15 teacher = line[6].replace('\n', '') 16 subject = line[10].replace('\n', '') 17 semester = line[12].replace('\n', '') 18 credit = line[16].replace('\n', '') 19 data = [teacher, subject, semester[-2:], credit] 20 data_list.append(data) 21 22 return data_list

text

12020/04/09(木)16:02 2 3科目ナンバー 0000000000 4 5教員名 6 7教員名の名前 8 9科目名 10 11科目の名前 12 13開講年度学期 2020年度 前期 14 15単位数 16 171

text

12020/04/09(木)15:07 2 3科目ナンバー 4 5000000000 6 7開講年度学期 2020年度 前期 8 9科目名 10 11科目の名前 12 13教員名 14 15教員の名前 16 17単位数 18 192

試したこと

現状テキストの行番号を指定して取得していますが、それだと当然ですがうまくいきません。

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

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

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

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

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

guest

回答2

0

科目ナンバー 0000000000 というように、同じ行にある場合も考えるのであれば、正規表現を使う必要があるでしょう。こういうやり方も覚えておいてください。

python

1import re 2 3def read_text(filename): 4 with open(filename) as f: 5 text_data = f.read() 6 return text_data 7 8def check_date(text_data): 9 m = re.search(r'(\d{4}/\d{2}/\d{2}(.)\d{2}:\d{2})', text_data) 10 if m: 11 return m.group() 12 else: 13 return '' 14 15def check(item, text_data): 16 m = re.search(item + '[ \u3000\n]+([^\n]+)\n*', text_data) 17 if m: 18 return m.groups()[0] 19 else: 20 return '' 21 22def pickup_from_text(text_data): 23 result = {'日時' : check_date(text_data)} 24 for item in ['科目ナンバー', '教員名', '科目名', '開講年度学期', '単位数']: 25 result[item] = check(item, text_data) 26 return result 27 28if __name__ == '__main__': 29 import sys 30 print(pickup_from_text(read_text(sys.argv[1]))) 31

今回のデータには全角空白が入っていたので正規表現の中に'\u3000'も入れる必要がありました。

fc2LiveAdultさんの書いた二つのデータをdata1.txt、data2.txtとしたときの実行結果は以下です。

python

1teratail> python pickupfromtext.py data1.txt 2{'日時': '2020/04/09(木)16:02', '科目ナンバー': '0000000000', '教員名': '教員名の名前', '科目名': '科目の名前', '開講年 度学期': '2020年度 前期', '単位数': '1'} 3teratail> python pickupfromtext.py data2.txt 4{'日時': '2020/04/09(木)15:07', '科目ナンバー': '000000000', '教員名': '教員の名前', '科目名': '科目の名前', '開講年度学期': '2020年度 前期', '単位数': '2'}

投稿2020/12/28 16:11

ppaul

総合スコア24670

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

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

fc2LiveAdult

2020/12/28 16:50

お二方ともありがとうございました! 正規表現。。勉強してみます。。
guest

0

ベストアンサー

下記の基本的な考え方
ファイルを読み取って全行をリストに格納(最初の20行でもいいかもしれないですが)。
行を1つ1つ調べて、たとえばその行が 「科目名」ならば「科目名の行数(subject)」としてマーク。

あとから各行について、2行後を真データとして採用します。(ただし前期後期はその行の改行を除く最後2文字)

def get_data(): # テキストファイル取得 this_path = os.getcwd() + '\app\Http\Python\text' files = glob.glob(this_path + '\*.txt') # データ取得 data_list = [] for file in files: with open(file, 'r', encoding="utf-8") as f: line = f.readlines() # ここから修正 for i, text in enumerate(line): text = text.replace('\n', '') if text == '教員名': teacher = i elif text == '科目名': subject = i elif text[:4] == '開講年度': semester = i elif text == '単位数': credit = i data = [line[teacher+2], line[subject+2], line[semester][-3:], line[credit+2] ] data_list.append(data) return data_list

上記の残りのブラッシュアップの余地として、
・教員名、科目名~とかのテキストがきちんとスキャンできていなかった時のエラートラップ
・条件文字が最後から2行前以降にあったときエラートラップ
とかですかね。

投稿2020/12/28 15:13

編集2020/12/28 15:26
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問