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

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

新規登録して質問してみよう
ただいま回答率
85.50%
スクレイピング

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

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

Python

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

Q&A

1回答

993閲覧

BeautifuSoupでスクレイピング結果のprint()とCSV保存

mosmoss

総合スコア5

スクレイピング

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

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

Python

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

0グッド

0クリップ

投稿2019/09/04 08:08

前提・実現したいこと

tdnetのXBRL(拡張子.htmのファイル)の読み、BeautifuSoupでスクレイピングした結果を
print()で表示しています。

これの出力結果をCSVに書き出したいのですが、
CSVの作成ができません。
printでの出力はエラーもでず問題ないのですが、
printで出力しつつ、その結果内容をCSVにも保存させることはできるのでしょうか。

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

NameError: name 'df' is not defined

該当のソースコード

Python3

1import datetime 2 3from urllib.request import urlopen 4from bs4 import BeautifulSoup 5import pandas as pd 6import requests 7import os 8import zipfile 9import re 10 11def fn_parse(sic , xbrl_path): 12 13 # htmファイル読み込み 14 ff = open( xbrl_path , "r" ,encoding="utf-8" ).read() 15 soup = BeautifulSoup( ff ,"html.parser") 16 17 #ファイル名には命名規則があるので、そこから属性情報等を取得 18 rpt_nm = xbrl_path.split("-")[1] 19 print(rpt_nm ) 20 21 #ix:nonnumeric 22 print( "■ix:nonnumeric" ) 23 nms = soup.find_all("ix:nonnumeric") 24 for nm in nms: 25 # print(str(nm.get("name"))) 26 27 lst = ['SecuritiesCode','URL','CompanyName','FilingDate','FiscalYearEnd'] 28 lst = lst + ['AccountingStandardsDEI','EDINETCodeDEI','CurrentFiscalYearStartDateDEI','CurrentPeriodEndDateDEI'] 29 x = [print(i,nm.text) for i in lst if i in "tse-ed-t:"+nm.get("name") ] 30 31 #ix:nonfraction 32 elems = soup.find_all("ix:nonfraction" ) 33 print( "■ix:nonfraction" ) 34 for elem in elems: 35 print(str(elem.get("name"))) 36 print(str(elem.get("contextref"))) 37 #print(str(elem.get("decimals"))) 38 #print(str(elem.get("scale"))) 39 #print(str(elem.get("unitref"))) 40 print(elem.text) 41def fn_htm(sic,fn): 42 43 url = 'https://www.release.tdnet.info/inbs/' + str(fn) 44 #XBRLダウンロード 45 fn = str(sic) +".zip" 46 os.system("wget -O " + str(fn) + " " + str(url)) 47 48 # ZIP解凍 49 with zipfile.ZipFile( str(fn), 'r' ) as myzip: 50 infos = myzip.infolist() 51 for info in infos: 52 base, ext = os.path.splitext(info.filename) 53 # htmの読み込み 54 if ext == '.htm': 55 if str(base).find('Summary')>0 or str(base).find('Attachment')>0 : 56 myzip.extract(info.filename) 57 print('■□■' + info.filename) 58 dict = fn_parse(sic , info.filename) 59 60def fn_make_df(url): 61 62 #変数設定 63 a,b,c,d,e,f = [],[],[],[],[],[] #リストを6つ用意 64 df = pd.DataFrame() #取得結果格納用のデータフレーム 65 66 #ページの閲覧 67 html = urlopen(url) 68 bsObj = BeautifulSoup(html, "html.parser") 69 tbl3 = bsObj.findAll("table")[3] 70 trs = tbl3.findAll("tr") 71 72 for tr in trs: 73 lst=[] 74 tds = tr.findAll('td') 75 for td in tds: 76 #各tdの値を各リストに各々格納 77 if td.get("class")[1] =="kjTime":a += [td.text ] #開示時刻 78 if td.get("class")[1] =="kjCode":b += [td.text ] #コード 79 if td.get("class")[1] =="kjName":c += [td.text ] #社名 80 if td.get("class")[1] =="kjTitle": d += [td.text ] 81 if td.get("class")[1] =="kjTitle": #pdfのリンクURL 82 e += [td.a.get("href") ] if td.a is not None else [td.a ] 83 if td.get("class")[1] =="kjXbrl" : #XBRLのDLリンク 84 f += [td.a.get("href") ] if td.a is not None else [td.a ] 85 86 #取得結果格納リスト群からデータフレーム生成 87 df = pd.DataFrame( 88 data={'A': a, 'B': b, 'C': c, 'D': d, 'E': e, 'F': f}, 89 columns=['A', 'B', 'C', 'D', 'E', 'F']) 90 return df 91 92def fn_tkjkj(date): 93 94 # URL文字列の生成 95 url0 = 'https://www.release.tdnet.info/inbs/' 96 url1 = url0 + 'I_list_{}_{}.html'.format('001',date) 97 print(url1) 98 99 # 該当URLを閲覧 100 html = urlopen(url1) 101 bsObj = BeautifulSoup(html, "html.parser") 102 tbl1 = bsObj.findAll("table")[1] 103 104 dv1 = tbl1.findAll("div",{"class":"kaijiSum"}) 105 dv2 = tbl1.findAll("div",{"class":"pager-O"}) 106 dv3 = tbl1.findAll("div",{"class":"pager-M"}) 107 108 if dv1 ==[]: 109 print('開示0件') 110 else: 111 #print(str(dv1).split('全')[1].split('</')[0]) 112 lst =[ int(i.string) for i in dv3] 113 if lst ==[]: 114 df = fn_make_df(url1) 115 # print(df) 116 else: 117 # ページ数の取得 118 mxpg= max(lst) 119 print( mxpg ) 120 121 # 再度URL文字列の生成 122 for i in range(mxpg): 123 s = str(i + 1) 124 print(date,url0 ) 125 url1= url0 + 'I_list_{}_{}.html'.format(s.zfill(3) , str(date)) 126 print(s , url1)# 127 128 # ページを逐次閲覧して開示情報を取得 129 df = fn_make_df(url1) 130 131 # 短信XBRLに限定(短信訂正は除外、XBRLの付いてないものも除外) 132 df = df[df["D"].str.contains('短信')] 133 df = df[~df["D"].str.contains('訂正')] 134 df = df[~df["F"].isnull()] 135 136 # XBRL(htm)の読み取り 137 x = [fn_htm(sic,fn) for sic, fn in zip(df["B"], df["F"])] 138 #x = [print(sic,fn) for sic, fn in zip(df["B"], df["F"])] 139 140 141# main 142if __name__ == '__main__': 143 144 # 日付 145 date = datetime.datetime.today().strftime("%Y%m%d") 146 fn_tkjkj(date) 147 148 149filename = "company_list.csv" 150df.to_csv(filename, encoding = 'utf-8-sig') 151files.download(filename)

試したこと

CSVへの書き出しを調べましたが、
printと一緒に出力する方法がわかりません。

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

google colaboratoryで実行

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

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

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

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

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

meg_

2019/09/04 12:48

エラーメッセージは全文掲載いただかないとどこで起きてるエラーか分かりません。
guest

回答1

0

「printでの出力はエラーもでず問題ない」とのことですが、関数内でのprintでは出力されるということでしょうか?

みた感じ、エラー文にもある通り関数外でdfが定義されてませんので、関数の外(例えばfilename = "company_list.csv" の上など)でprint(df)をすると同様にエラーが出ると思います。

return文を書くだけでなく、それを変数に格納してあげないといけないので、

python

1 # 日付 2 date = datetime.datetime.today().strftime("%Y%m%d") 3 fn_tkjkj(date)

ここを

python

1 # 日付 2 date = datetime.datetime.today().strftime("%Y%m%d") 3 df = fn_tkjkj(date)

にすれば上手くできると思います。

投稿2019/09/04 08:47

llr114

総合スコア203

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

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

mosmoss

2019/09/04 09:50

ご回答ありがとうございます! 変数に格納する形にしたのですが、下記のエラーが出てしまいます。 AttributeError: 'NoneType' object has no attribute 'to_csv' これは数の値がNoneだから、to_csvのメソッド(?)が使えないと理解しました。 やはり「dfが定義できていない」状態なのでしょうか... ただ、print(df)でも値は出力されるのでイマイチ理解ができない状態です。 立て続けの質問となり申し訳ございませんが、 解決策がわかれば教えていただければと思います。
llr114

2019/09/04 09:57

print(type(df)) これの出力結果を教えて頂いてもいいでしょうか?
mosmoss

2019/09/04 10:18

以下出力結果です(途中中略しております) 「'NoneType」が出力されているとうことは、やはり値が存在しないということでしょうか... 1 https://www.release.tdnet.info/inbs/I_list_001_20190904.html ■□■XBRLData/Summary/tse-qnedjpsm-22170-20190904322170-ixbrl.htm qnedjpsm ■ix:nonnumeric FilingDate 2019年9月4日 CompanyName モロゾフ株式会社 SecuritiesCode 22170 URL http://www.morozoff.co.jp FilingDate 2019年9月12日 FiscalYearEnd 2020-01-31 ■ix:nonfraction tse-ed-t:NetSales CurrentAccumulatedQ2Duration_NonConsolidatedMember_ResultMember ~中略~ 20190904 https://www.release.tdnet.info/inbs/ 2 https://www.release.tdnet.info/inbs/I_list_002_20190904.html <class 'NoneType'>
llr114

2019/09/04 10:34

そちらの出力結果はどこで実行したものでしょうか? filename = "company_list.csv" の上あたり(関数の外)で、 print(df) print(tyoe(df)) の二つを実行した結果、 print(df)は上記の出力が出て、print(tyoe(df))は<class 'NoneType'>を出力した、ということでしょうか?
mosmoss

2019/09/04 10:48

わかりにくく申し訳ございません。 記載いただいているように、 filename = "company_list.csv"の上(関数の外)で、 それぞれ回した結果、 print(df):上記の出力、 print(type(df)):<class 'NoneType'>が出力されます。
llr114

2019/09/04 10:59

print(df) print(type(df)) この二つの上に、 df = pd.DataFrame(df) を書いた場合出力はどうなるでしょうか?
mosmoss

2019/09/04 12:12

print(df)の場合以下が出力されて Empty DataFrame Columns: [] Index: [] print(type(df))の場合、以下の出力になります。 <class 'pandas.core.frame.DataFrame'>
llr114

2019/09/04 14:47

確認有難うございます。 def fn_tkjkj(date): の関数の最後(if文の中とかでは無く、fn_make_dfと同じような箇所)に return def をつけてみてください。 先ほどの df = pd.DataFrame(df) は決して構わないので、同様に print(df) print(type(df)) の出力を教えていただきたいです。 また、その後 files.download(filename) の箇所でエラーが出るようでしたら、そこの行を消してみてください。 無くてもcsvが書き出されるはずです。
mosmoss

2019/09/05 11:12

すみません、色々格闘しておりました。 print(df) の出力  Empty DataFrame  Columns: [A, B, C, D, E, F]  Index: [] print(type(df)) <class 'pandas.core.frame.DataFrame'> また、CSVは書きだされました!ありがとうございます。 ただ、fn_make_df(url)で呼び出したデータのみが(A,B,C,D,D,F)に出力されており、 本来希望するその次のfn_tkjkj(date)で読み込んだデータは出力されません... これはやはり、fn_tkjkj(date)を拾えていないのでしょうか....
llr114

2019/09/05 12:28

fn_tkjkj(date)で読み込んだデータというのは for i in range(mxpg): s = str(i + 1) print(date,url0 ) url1= url0 + 'I_list_{}_{}.html'.format(s.zfill(3) , str(date)) print(s , url1)# # ページを逐次閲覧して開示情報を取得 df = fn_make_df(url1) # 短信XBRLに限定(短信訂正は除外、XBRLの付いてないものも除外) df = df[df["D"].str.contains('短信')] df = df[~df["D"].str.contains('訂正')] df = df[~df["F"].isnull()] # XBRL(htm)の読み取り x = [fn_htm(sic,fn) for sic, fn in zip(df["B"], df["F"])] #x = [print(sic,fn) for sic, fn in zip(df["B"], df["F"])] ここの中の df = fn_make_df(url1) で取得する値のことでしょうか? if lst ==[]: df = fn_make_df(url1) # print(df) else: # ページ数の取得 mxpg= max(lst) print( mxpg ) ここのif文でlst ==[]と判定されてしまっている気がするのですが、いかがでしょうか? print( mxpg ) は出力されていますでしょうか? if lst ==[]: print('lstが空') df = fn_make_df(url1) # print(df) else: # ページ数の取得 mxpg= max(lst) print( mxpg ) のように各所でメッセージをprintするようにして、どのように分岐が進んでいるのか確認してみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問