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

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

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

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

Q&A

解決済

4回答

1049閲覧

textfileを行毎に読み出しが出来ない

shiraishi_kiich

総合スコア20

Python 3.x

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

0グッド

0クリップ

投稿2022/01/05 00:24

前提・実現したいこと

WEBサイトからダウンロードしたTextfileを一行毎に読み出したいと思いました。実行結果は一文字毎に読み出していいました。
コード中最終的には「f」に代入したつもりです。これをprint(f)でターミナルに出力すると下のように正常に見えます。
N-S E-W Contract N-S E-W MP
B04 B30 5C N 5 400 27
B31 B05 2NT S 5 210 26
B18 B13 4C N 5 150 24.5
A09 A20 3C N 5 150 24.5
B24 B12 4C N 4 130 22
A02 A22 4C N 4 130 22
A07 A15 4C N 4 130 22
A03 A23 3C N 3 110 20
A19 A11 4S E-2 100 19
B07 B32 3S E-1 50 13
A17 A12 3S E-1 50 13
A21 A04 3S E-1 50 13
A24 A01 3S E-1 50 13
B03 B20 3S E-1 50 13
A05 A16 3S E-1 50 13
B23 B06 3S E-1 50 13
B25 B16 3S E-1 50 13
B26 B01 3S E-1 50 13
B09 B22 3S E-1 50 13
A10 A18 3S E-1 50 13
B28 B10 5C N-1 50 7
B19 B15 6C N-2 100 5.5
B17 B11 5Cx N-1 100 5.5
A14 A06 3S E 3 140 2.5
B14 B27 3S E 3 140 2.5
B02 B29 3S E 3 140 2.5
B21 B08 3S E 3 140 2.5
A13 A08 4S E 4 420 0
しかし
for line in f:
print(line)
で行毎に取り出そうとして printした内容は以下、上の行単位出力の最後の行が文字単位で出力されて見える。(され以前は表示範囲を超えているようで見えない。
0
8

4
S

E

4

4
2
0

0

print(type(f)) は <class 'str'> ですが print(hasattr(f, "line")) を見ると False になっています。
私にはどこで間違っているのか全く解りません。terxt文書のtyoeはstr と思っていましたが間違いなのでしょうか。
■■動作確認時に以下の期待しない動作がありました。

for line in f:で取り込んだ内容が行単位でなく、文字単位で取り込まれている。

該当のソースコード

python3.9

1from typing import Text 2import requests 3from bs4 import BeautifulSoup as bs4 4import dataclasses 5 6with open('tyest.txt', 'w') as f: 7 load_url = "https://sendaibc.sakura.ne.jp/traveling/trv_2017aob_1.txt" 8 html = requests.get(load_url) 9 soup = bs4(html.content,"html.parser") 10print(f) 11print(type(f)) 12 13f = soup.text 14 print(type(f)) 15 16print(f) #これはTextfileとしてターミナルに正常に出力される 17 18for line in f: #行単位でなく、文字単位にターミナルに表示される 19 print(line) 20print(type(f)) 21print(hasattr(f, "line"))

試したこと

他の行単位出力tン位ここに問題に対して試したことを記載してください。

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

ここにより詳細な情報を記載してください。

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

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

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

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

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

TakaiY

2022/01/05 01:18

回答への質問に、 追加)netをみると for line in f: print(line) でtext文書壱行毎に読み出す書式として記載されています。 とありますが、出展を教えていただけますか、 何を根拠にどのような結果を期待しているのかがわかれば的確な説明ができると思いますので。
guest

回答4

0

ベストアンサー

質問に回答いただいたので、説明してみます。
基本的には他の方の回答で説明されていることと同じ内容です。

質問の回答にあるサイトの説明は、ファイルを開いたときのものですね。
ファイルを開いたときに返るのは「ファイルオブジェクト」です。
質問のコードにもいくつか出てくるtype()関数で調べればそれがstrでないことはわかると思います。

ファイルオブジェクトはリスト「のように」扱われると、そのファイルの内容を1行ずつ出すようにできています(__next__メソッドの返りが1行分の文字列ということ)。

なので、以下のコードは内容を1行ずつ出力します。

python

1for line in text_file: 2 print ("「" + line.strip() +"」")

質問の内容の方ですが、理解が間違えています。

python

1with open('tyest.txt', 'w') as f: 2 load_url = "https://sendaibc.sakura.ne.jp/traveling/trv_2017aob_1.txt" 3 html = requests.get(load_url) 4 soup = bs4(html.content,"html.parser")

この部分を見ると、たしかにtyest.txtというファイルを開いてオブジェクトを作り、fでアクセスできるようにしていますが、そのfを使っていません。
このwithブロックを抜けると、fは無効になってしまいます。
ということで、ここにあるwithブロックは、withブロックとしての意味がありません。

soup変数の内容はここではfには関係ありませんが、bsにより取得されたURLの内容が入っています。

python

1f = soup.text 2 3print(f) #これはTextfileとしてターミナルに正常に出力される 4 5for line in f: #行単位でなく、文字単位にターミナルに表示される 6 print(line)

この部分の接頭で、fにはsoup.textの返り値 = urlで指定されたものの「内容=文字列」が入ります。

文字列は「リストのように」扱われると、含まれている文字を1文字ずつ出すようになっているので、質問のような動作になります。


URLの内容を取得してきて、1行ごとに処理したいのであれば、だいたいこんな感じにすればいいでしょう。 with文は使いません。
(他の方の回答と同じですが)

python

1load_url = "https://sendaibc.sakura.ne.jp/traveling/trv_2017aob_1.txt" 2html = requests.get(load_url) 3soup = bs4(html.content,"html.parser") 4f = soup.text 5 6for line in f.splitlines(): 7 print(line)

文字列を行に分割するのにsplitlines()を使ってみました。

投稿2022/01/05 02:40

TakaiY

総合スコア12743

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

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

shiraishi_kiich

2022/01/05 04:02

ありがとうございました。回答の通りに修正して期待通りに動作しました。ちなみに全てwith文の中で処理すればよかったのでしょうか。Taskaiyさんのように丁寧に説明して頂かないと理解できないレベルです。 今後はlineを使用してtextdataを加工していきますがその段階でも判らない事がまだまだありそうです。 よろしくお願いいたします。
TakaiY

2022/01/05 04:52

「全てwith文の中で処理すればよかったのでしょうか」 回答に書いたように、違います。 with分は、ファイル(など)を開いてその内容を読んだり書き込んだりするために使います。 beautifulsoupを使ってweb上のものを扱うときには使いません。 ファイル(など)の(など)にWeb上の物など他のものも入れることもできますが、それについてはもっと理解してから取り組むのがいいでしょう。
guest

0

terxt文書のtyoeはstr

その理解で正しいです。提示コードでのf改行文字が含まれた文字列です。
よってfをそのままprintすると、見た目は自然なカタチで見えます。

ただしstrforで走査すると、各要素は文字となります。
よってそれらをprintすると1文字ずつ出力されます。

1行毎に処理したいのであればstrであるfを改行でsplitすればよいです。

なお、提示コードではwith で開いたファイルオブジェクトをfとしていますが、実際には使われていません。
取得した.txtの内容をファイルとして保存したいだけなら単にf.write(soup.text)すればよいです。

Python

1 2text = 'a b\nc d\n' 3print(f'[{text}]') 4#[a b 5#c d 6#] 7 8for c in text: 9 print(f'[{c}]') 10#[a] 11#[ ] 12#[b] 13#[ 14#] 15#[c] 16#[ ] 17#[d] 18#[ 19#] 20 21lines = text.split('\n') 22for line in lines: 23 print(f'[{line}]') 24#[a b] 25#[c d] 26#[] 27 28with open('tyest.txt', 'w') as f: 29 f.write(text)

投稿2022/01/05 00:55

can110

総合スコア38256

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

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

shiraishi_kiich

2022/01/05 01:37

21行にf.write(soup.text)を追加し実行すると Traceback (most recent call last): File "c:\Users\shiraishikiichi\pytext\scrap.py", line 21, in <module> f.write(soup.text) AttributeError: 'str' object has no attribute 'write' とエラーメッセージがでます。
can110

2022/01/05 01:48

ファイルを開いている間、つまりwith open(~:のブロック内で実行しないといけません。
guest

0

1行毎に、という事であれば以下の様にしてみてはどうでしょうか。

python

1from typing import Text 2import requests 3from bs4 import BeautifulSoup as bs4 4import dataclasses 5 6with open('tyest.txt', 'w') as f: 7 load_url = "https://sendaibc.sakura.ne.jp/traveling/trv_2017aob_1.txt" 8 html = requests.get(load_url) 9 soup = bs4(html.content,"html.parser") 10 f.write(soup.text) 11 12with open('tyest.txt', 'r') as f: 13 for line in f: 14 print(line.strip())

投稿2022/01/05 00:48

melian

総合スコア19703

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

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

shiraishi_kiich

2022/01/05 01:52

回答のようにすると下記エラーが表示されます。f.write(soup.text)は10行に追加。 エラーの一行目と、最後の行はどこで出ているのか判りません。 Some characters could not be decoded, and were replaced with REPLACEMENT CHARACTER. Traceback (most recent call last): File "c:\Users\shiraishikiichi\pytext\scrap.py", line 10, in <module> f.write(soup.text) UnicodeEncodeError: 'cp932' codec can't encode character '\ufffd' in position 0: illegal multibyte sequence
melian

2022/01/05 02:10

with open('tyest.txt', 'w') as f: を with open('tyest.txt', 'w', encoding='utf-8') as f: に変更するとどうなるでしょうか?
guest

0

python

1for line in f: #行単位でなく、文字単位にターミナルに表示される 2 print(line) 3

ではなく、

python

1print(f) 2

です。

for line in f:はfという文字列の各文字に対して処理を行うことになり、lineには文字一個が入ります。

投稿2022/01/05 00:36

ppaul

総合スコア24666

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

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

shiraishi_kiich

2022/01/05 00:43

print(f)ですと、f全体が表示されます。
shiraishi_kiich

2022/01/05 00:51

追加)netをみると for line in f: print(line) でtext文書壱行毎に読み出す書式として記載されています。
ppaul

2022/01/05 01:17

そうですね。読み間違えていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問