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

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

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

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

Python

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

Q&A

2回答

1486閲覧

Python スクレイピング 更新情報出力

hfjdsfh_48

総合スコア13

スクレイピング

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

Python

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

0グッド

0クリップ

投稿2021/01/25 13:30

編集2021/01/25 23:57

Pythonを用いて、銘柄の適時開示情報ページ(JSON形式)
(https://webapi.yanoshin.jp/webapi/tdnet/list/8818.json2?limit=100)
で、更新情報があれば、会社名とURLを出力したく、以下のコーディングを行いました。
この場合、一つの銘柄の場合には対応していますが、銘柄が複数の場合、最新の更新情報が無限に出力されてしまいます。
複数の銘柄の場合でも、一度出力した最新の更新情報は出力されないようにするにはどのようにすれば良いでしょうか。

Python

1import schedule 2import time 3import json 4import requests 5 6old_file="test.txt" 7 8def job(): 9 tr="" 10 resp = requests.get("https://webapi.yanoshin.jp/webapi/tdnet/list/8818.json2?limit=100") 11 data = resp.json() 12 result = [] 13 for item in data.get("items", []): 14 tdnet = item.get("Tdnet") 15 if tdnet is None: 16 break 17 published_at = tdnet.get("pubdate") 18 # 最新の日時の開示のみ取得する。 19 if tr == '': 20 tr = published_at 21 22 elif published_at != tr: 23 break 24 25 result.append( 26 dict( 27 name = tdnet.get("company_name"), 28 published_at = published_at, 29 title = tdnet.get("title"), 30 url = tdnet.get("document_url") 31 ) 32 ) 33 global old_file 34 if tr == '': 35 print("データを取得できませんでした") 36 elif tr == old_file: 37 pass 38 #print("更新なし。 直近の取得日時:", tr) 39 40 else: 41 print(f"日時: {tr}") 42 for r in result: 43 data=f"{r['name']} {r['title']} {r['url']}" 44 print(data) 45 46 old_file=tr 47 48schedule.every(1).seconds.do(job) 49while True: 50 schedule.run_pending() 51 time.sleep(1) 52 53job() 54

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

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

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

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

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

t_obara

2021/01/26 01:07

仕様を明確にしましょう。複数の銘柄の場合に一度出力した最新の更新情報は出力されない条件を考える必要があります。どのような条件になるとお考えですか?
t_obara

2021/01/26 04:33

その仕様を満たすようにプログラミングをしたのにできないのか、仕様を満たすようにプログラムを記述できないのかどちらですか?
hfjdsfh_48

2021/01/26 04:45

仕様を満たすようなプログラムを記述できません
t_obara

2021/01/26 04:50

複数の銘柄の場合に、「一度出力した最新の情報を変数として保存」ができないということでしょうか?
hfjdsfh_48

2021/01/26 04:58

はい。複数の銘柄の場合は、変数を複数用意すればうまくいくと思うのですが、銘柄が増えたときにまた変数を増やすのは効率的でないと思いました。そもそも変数を複数用意しなくてもよい書き方があれば教えてください。
guest

回答2

0

APIが返すデータの中に「id」というものがあります。
これは、会社を超えて、1つ1つのデータごとに異なる番号です。

したがってデータを取得したときにidを格納しておき、
次にデータを取得した場合には、取得したデータのidを取得済みのidと比較し、
存在しないidであればそれを(新データとして)表示するようにすればよいでしょう。

考え方:

python

1 2 # 差分データを格納するリスト 3 new_records = [] 4 5 for record in records: 6 id = record["id"] 7 # とってきたデータ(record)のidがデータベースの中にない場合は、 8 if id not in database: 9 # databaseにそのデータを格納する。 10 database[id] = record 11 # new_recordsにも追加する。 12 new_records.append(record) 13 14 return new_records

 

コード例: 以下db.py とmain.pyを同じ場所に置いておく。
db.py

python

1# db.py 2# 取得したデータ(レコード)を格納するデータベース擬きの辞書 3db = dict()

 
main.py

python

1# main.py 2 3import requests 4import schedule 5import time 6 7 8import db 9 10def get_data(company_code, limit:int=10): 11 ''' 12 適時開示データを取得する。 13 Args: 14 company_code (int): 証券コード 15 limit (int): 一度に取得するデータの数の上限 16 Returns: 17 list(dict) or list(None): 適時開示データのリスト 18 ''' 19 resp = requests.get(f"https://webapi.yanoshin.jp/webapi/tdnet/list/{company_code}.json2?limit={limit}") 20 data = resp.json() 21 22 items = data.get("items") 23 if not items: 24 return [] 25 # データ形式が古い場合に対応 26 if items[0].get("Tdnet") is None: 27 if items[0].get("id") is None: 28 return [] 29 else: 30 return [item.get("Tdnet") for item in items] 31 return data.get("items",[]) 32 33 34def select(record, keys): 35 ''' 36 指定されたレコードから、keysに指定された列データをリストにして返す。 37 Args: 38 record (dict) : 適時開示データ1行 39 keys (iterable(str)): キー名 40 Returns: 41 list(str): 指定されたレコードの、指定されたキー名に該当する列 42 ''' 43 return [record.get(key) for key in keys] 44 45 46def update_db(records): 47 ''' 48 Args: 49 records(list(dict)) : APIからとってきた適時開示データのリスト 50 Returns: 51 list(dict) or list(None) : 更新前のデータベースになかったレコードのリスト 52 ''' 53 new_records = [] 54 55 for record in records: 56 id = record["id"] 57 if id not in db.db: 58 db.db[id] = record 59 new_records.append(record) 60 return new_records 61 62def job(codes): 63 # 各々の証券コードごとに・・・ 64 for code in codes: 65 # API経由で適時開示データ(レコード)をとってきて・・ 66 records = get_data(code) 67 # データベース内の取得済みのデータと比較し、新しいレコードのみ抽出する。 68 new_records = update_db(records) 69 # 新しいレコードの内容を出力する。 70 for record in new_records: 71 pubdate, title, name, url = select(record, ['pubdate', 'title','company_name','document_url']) 72 print(f"{pubdate}: {name} {title} {url}") 73 74# 取得する銘柄の証券コードを指定 75target_codes = [7974, 8818] 76 77# サーバー負荷を考慮して10分ごとの取得としています。 78# 適時開示はツイッターみたいに頻繁に更新されるものではありませんから、1秒毎の更新間隔は短すぎると思います。 79schedule.every(10).minutes.do(job, target_codes) 80 81while True: 82 schedule.run_pending() 83 time.sleep(1)

投稿2021/01/26 13:59

編集2021/01/26 14:20
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

hfjdsfh_48

2021/01/27 04:18

ありがとうございます。Idを格納するリストを作れば思うように動作しました。ご教授いただいたコード例が自分で理解できなかったので、別のやり方をコーディングしました。 import requests import schedule import time import datetime id_list=[] def job(): resp = requests.get(f"https://webapi.yanoshin.jp/webapi/tdnet/list/1326-3960-8818.json2?limit=10") data = resp.json() result = [] d_today = datetime.date.today() sdate = d_today.strftime('%Y-%m-%d') for item in data.get("items", []): company_id=item.get("id") pubdate=item.get("pubdate")[:-9] if sdate!=pubdate: break elif company_id in id_list: break else: id_list.append(company_id) result.append( dict( pubdate=item.get("pubdate"), name = item.get("company_name"), title = item.get("title"), url = item.get("document_url") ) ) for r in result: data=f"{r['pubdate']} {r['name']} {r['title']} {r['url']}" print(data) #以下Lineで通知する処理 schedule.every(1).seconds.do(job) while True: schedule.run_pending() time.sleep(1) job()
guest

0

リストを利用すると良いです。以下のような感じです。

python

1 previous_text = [] 2 3 for ...: 4 5 if brand_text in previous_text: 6 # exist 7 else 8 # new 9 previous_text.append(brand_text) 10 11 12

投稿2021/01/26 10:35

t_obara

総合スコア5488

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

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

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

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問