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

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

ただいまの
回答率

88.80%

pythonで \r\n が削除できない

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 129

スクレイピングで取得した記事のリストから余分な \r\n を削除させたいのですが、次のエラーを吐き出してしまいました。

AttributeError: 'list' object has no attribute 'replace'


使用環境
GoogleCrome 86.0.4240.75(64bit)
JupyterLab 2.1.5
JupyterLabのノートブックでプログラムを記述

問題の記事はこのようになります。

#!/usr/bin/env python
# coding: utf-8

from bs4 import BeautifulSoup
import urllib.request as req
import pandas as pd
import numpy as num
import re


url = "https://www.msn.com/ja-jp"
response = req.urlopen(url)


soup = BeautifulSoup(response, 'html.parser')
lists = soup.find_all(href=re.compile("/ja-jp/news")) #パスはサイトの右下に表示される
lists[1:21]


select = []
url_select = []

for list in lists:
    select.append(list.string)
    url_select.append(list.attrs['href']) 


selected = select.replace('\r\n','')
selected


最後のselect.replaceを、select.strip()としてみたり、select.re(r'(.+)\r\n')としてみましたが、エラーはいずれも上記の通りでした。
エラーの意味を察するに、指定のオブジェクトは属性を持たないということでしょうか? だとしても、どのように対処すればいいのか分かりません。
どうかお力をいただきますように、なにか分かれば教えていただければ幸いです。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

listは、組み込み関数とかぶるので、別の名前lstとかを使いましょう。

実際に動かしてみると、lst.stringがNoneなものがちらほら取得できるので、それらを取り除いてからreplaceしたものをappendすりゃいいのではないかな。

for lst in lists:
    if lst.string:
        select.append(lst.string.replace('\r\n', ''))
        url_select.append(lst.attrs['href'])

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/10/18 01:27

    Daregada様
    ありがとうございます! 上記の記述でうまくいきました。
    おっしゃる通りに "list" と定義するのはあまりにユニークではないですね。ちょっと気になってはいたのですが、あまり関係のないことだと無視を決め込んでいました。
    先のotn様も仰っていたように文字列に対してreplaceしなくてはならないとのことでしたが、その記述方法がいまいちピンときませんでした。なるほどif文の条件に lst.string と、まず記述するのですね。ここはそのような解釈の仕方が、自分は苦手かもしれません……。またそのうえで lst.string.replace と関数をつなげて書くという方法もあるのですね。オブジェクト名につなげることはできても、関数通しを繋げることは単純にドットではできないと思っていました。ドットで繋げられるのは同じクラス内のメソッドという関係性だけだと思っていました。
    素早い御回答ありがとうございますm(__)m

    キャンセル

  • 2020/10/18 01:37

    > なるほどif文の条件に lst.string と、まず記述するのですね
    ちがいます。listsからひとつのlstを取り出すと、lst.stringには、通常は文字列が入っていますが、たまにNoneが得られます。Noneに対してreplaceを使うとエラーになるため、「lst.stringがNoneでなければ」という条件を短く書いているのです。lst.stringが全て文字列を得られるのであれば、このifは不要で、いきなりlsr.string.replaceすればいいです。

    キャンセル

  • 2020/10/18 02:07

    わかりましたm(__)m
    よく見ると、記事の間にところどころあったNoneが、そういえば消えていました。Noneは 文字列型ではないため、ということですね。
    すごく理解が深まりました! ありがとうございます!

    キャンセル

0

selectは文字列じゃなくてリストなので、replaceできません。

リストの要素である文字列に対して、replaceしましょう。

というか、select.appendする前のlist.string(これは文字列)に対してreplaceすればいいかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/10/18 01:45

    otn様
    ご助言ありがとうございます。
    文字列に対して replace するということでしたが、ではリスト型として定義されたのはどこからなのかと考えたとき、for文からという認識で合っているでしょうか? またその解釈で合っているとするならば、答えの一つであるfor文の中で、lst.string.replace('\r\n', '') と定義できるのは何故なのか、もし可能でしたら、その解釈を教えていただけないでしょうか。
    御面倒お掛け致しますm(__)m

    キャンセル

  • 2020/10/18 08:00

    > リスト型として定義されたのはどこからなのか

    select = []

    > lst.string.replace('\r\n', '') と定義できるのは何故なのか

    list は soup.find_all の結果である「ノードのリスト」の1つの要素なので、
    list は「bs4のノード」。list.string は文字列です。

    常に「この変数は何型なのか?このメソッドの返す物は何型なのか?」を考えながらプログラムを書きましょう。

    キャンセル

  • 2020/10/18 10:56

    find_all がリスト型だったことを知らず、また何型かの意識もなく記述していた状態でしたので、今回はとてもためになりました。
    まだメソッドや関数のそれぞれの役目や特徴に無知な部分が多いので、慣れるまでは別ファイルにでも型の判定した一覧を掲示してそれを見ながら進めてみようと思います。
    とても感謝しております。ありがとうございます!

    キャンセル

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

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る