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

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

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

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

Python

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

Scrapy

Scrapyは、Pythonで開発されたオープンソースソフトウェアです。スクレイピングという、Webサービスから必要な情報を取り出したり自動操作をしたりする技術を使うものです。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

Q&A

0回答

2280閲覧

AttributeError: 'NoneType' object has no attribute 'strip'

Nagao_Ryogo

総合スコア4

スクレイピング

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

Python

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

Scrapy

Scrapyは、Pythonで開発されたオープンソースソフトウェアです。スクレイピングという、Webサービスから必要な情報を取り出したり自動操作をしたりする技術を使うものです。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

0グッド

0クリップ

投稿2019/10/15 07:14

編集2019/10/15 07:19

前提・実現したいこと

Python、Scrapyともに初心者です。(UnityのC#やArduinoを触っていたくらいです)
チュートリアルとして、下記サイトのコードをそのままコピーしてスクレイピングを行おうとしたのですが、タイトルの通りのエラーメッセージが発生し、原因が分かりません。1~2時間ほど様々なサイトを調べて試行錯誤しましたが解決策が分からない状況です。
参考サイト:https://qiita.com/Chanmoro/items/f4df85eb73b18d902739

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

AttributeError: 'NoneType' object has no attribute 'strip'

該当のソースコード

Python

1# -*- coding: utf-8 -*- 2import scrapy 3 4 5class ScrapyBlogSpiderSpider(scrapy.Spider): 6 name = 'scrapy_blog_spider' 7 allowed_domains = ['blog.scrapinghub.com'] 8 9 start_urls = ['http://blog.scrapinghub.com/'] 10 11 def parse(self, response): 12 """ 13 レスポンスに対するパース処理 14 """ 15 # response.css で scrapy デフォルトの css セレクタを利用できる 16 for post in response.css('.post-listing .post-item'): 17 # items に定義した Post のオブジェクトを生成して次の処理へ渡す 18 yield post( 19 url=post.css('div.post-header a::attr(href)').extract_first().strip(), 20 title=post.css('div.post-header a::text').extract_first().strip(), 21 date=post.css('div.post-header.byline.span.date a::attr(href)').extract_first().strip(), 22 # if date is None: 23 # pass 24 ) 25 26 # 再帰的にページングを辿るための処理 27 older_post_link = response.css('.blog-pagination a.next-posts-link::attr(href)').extract_first() 28 if older_post_link is None: 29 # リンクが取得できなかった場合は最後のページなので処理を終了 30 return 31 32 # URLが相対パスだった場合に絶対パスに変換する 33 older_post_link = response.urljoin(older_post_link) 34 # 次のページをのリクエストを実行する 35 yield scrapy.Request(older_post_link, callback=self.parse) 36 pass

試したこと

参考サイト内で日付を取得する部分が下記のようになっており、これが最初にエラーをはいていたため
date=post.css('div.post-header span.date a::text').extract_first().strip(),
エラー文:TypeError: 'Selector' object is not callable

取得元のサイトの構造と指定しているパスにズレがあるのかな?と考えて、下記のように書き換えました。
そうなると、今回のエラーが発生しました。
date=post.css('div.post-header.byline.span.date a::attr(href)').extract_first().strip(),

見様見真似で修正したため、間違えているとは思うのですが、どこが間違えているのかがどうも理解できないです。

下記はスクレイピングするサイトの中で取得しようとしているデータに関連した部分だけ抽出したのものです。関係なさそうなところは省略してあります。
取得元サイト:https://blog.scrapinghub.com/

<div class="post-listing"> <div class="post-item"> <div class="hs-featured-image-wrapper"> <a href="https://blog.scrapinghub.com/web-scraping-questions-answers-part-1" title="" class="hs-featured-image-link"> <img src="https://cdn2.hubspot.net/hub/4367560/hubfs/DSC_0231.jpg?width=830&amp;name=DSC_0231.jpg" class="hs-featured-image" alt="DSC_0231"> </a> </div> <div class="post-header"> <h2><a href="https://blog.scrapinghub.com/web-scraping-questions-answers-part-1">Web Scraping Questions &amp; Answers Part I</a></h2> <div class="byline"> <span class="date"> <i class="fa fa-calendar-o"></i> <a href="https://blog.scrapinghub.com/web-scraping-questions-answers-part-1">October 10, 2019 </a> </span> <span class="author"> 省略 </span> <span class="custom_listing_comments"> 省略 </span> </div> </div> <div class="post-content"> 省略 <div class="read-more"> 省略 </div> </div> </div> </div>

補足情報:出力されたメッセージ全文(長いため、後半に載せました。)

2019-10-15 15:35:10 [scrapy.utils.log] INFO: Scrapy 1.5.1 started (bot: ten_min_scrapy) 2019-10-15 15:35:10 [scrapy.utils.log] INFO: Versions: lxml 4.1.1.0, libxml2 2.9.5, cssselect 1.0.3, parsel 1.4.0, w3lib 1.19.0, Twisted 18.9.0, Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)], pyOpenSSL 17.5.0 (OpenSSL 1.1.0g 2 Nov 2017), cryptography 2.2, Platform Windows-10-10.0.17763-SP0 2019-10-15 15:35:10 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'ten_min_scrapy', 'DOWNLOAD_DELAY': 3, 'HTTPCACHE_ENABLED': True, 'NEWSPIDER_MODULE': 'ten_min_scrapy.spiders', 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['ten_min_scrapy.spiders']} 2019-10-15 15:35:10 [scrapy.middleware] INFO: Enabled extensions: ['scrapy.extensions.corestats.CoreStats', 'scrapy.extensions.telnet.TelnetConsole', 'scrapy.extensions.logstats.LogStats'] 2019-10-15 15:35:10 [scrapy.middleware] INFO: Enabled downloader middlewares: ['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware', 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware', 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware', 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware', 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware', 'scrapy.downloadermiddlewares.retry.RetryMiddleware', 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware', 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware', 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware', 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware', 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware', 'scrapy.downloadermiddlewares.stats.DownloaderStats', 'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware'] 2019-10-15 15:35:10 [scrapy.middleware] INFO: Enabled spider middlewares: ['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware', 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware', 'scrapy.spidermiddlewares.referer.RefererMiddleware', 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware', 'scrapy.spidermiddlewares.depth.DepthMiddleware'] 2019-10-15 15:35:10 [scrapy.middleware] INFO: Enabled item pipelines: [] 2019-10-15 15:35:10 [scrapy.core.engine] INFO: Spider opened 2019-10-15 15:35:10 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2019-10-15 15:35:10 [scrapy.extensions.httpcache] DEBUG: Using filesystem cache storage in ドライブ名\ten_min_scrapy.scrapy\httpcache 2019-10-15 15:35:10 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023 2019-10-15 15:35:10 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to <GET https://blog.scrapinghub.com/robots.txt> from <GET http://blog.scrapinghub.com/robots.txt> 2019-10-15 15:35:10 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://blog.scrapinghub.com/robots.txt> (referer: None) ['cached'] 2019-10-15 15:35:10 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to <GET https://blog.scrapinghub.com/> from <GET http://blog.scrapinghub.com/> 2019-10-15 15:35:10 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://blog.scrapinghub.com/> (referer: None) ['cached'] 2019-10-15 15:35:10 [scrapy.core.scraper] ERROR: Spider error processing <GET https://blog.scrapinghub.com/> (referer: None) Traceback (most recent call last): File "ファイル保存先\python\python36-32\lib\site-packages\scrapy\utils\defer.py", line 102, in iter_errback yield next(it) File "ファイル保存先\python\python36-32\lib\site-packages\scrapy\spidermiddlewares\offsite.py", line 30, in process_spider_output for x in result: File "ファイル保存先\python\python36-32\lib\site-packages\scrapy\spidermiddlewares\referer.py", line 339, in <genexpr> return (_set_referer(r) for r in result or ()) File "ファイル保存先\python\python36-32\lib\site-packages\scrapy\spidermiddlewares\urllength.py", line 37, in <genexpr> return (r for r in result or () if _filter(r)) File "ファイル保存先\python\python36-32\lib\site-packages\scrapy\spidermiddlewares\depth.py", line 58, in <genexpr> return (r for r in result or () if _filter(r)) File "ファイル保存先\ten_min_scrapy\ten_min_scrapy\spiders\scrapy_blog_spider.py", line 20, in parse date=post.css('div.post-header.byline.span.date a::attr(href)').extract_first().strip(), AttributeError: 'NoneType' object has no attribute 'strip' 2019-10-15 15:35:10 [scrapy.core.engine] INFO: Closing spider (finished) 2019-10-15 15:35:10 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 1268, 'downloader/request_count': 4, 'downloader/request_method_count/GET': 4, 'downloader/response_bytes': 12888, 'downloader/response_count': 4, 'downloader/response_status_count/200': 2, 'downloader/response_status_count/301': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2019, 10, 15, 6, 35, 10, 908289), 'httpcache/hit': 4, 'log_count/DEBUG': 6, 'log_count/ERROR': 1, 'log_count/INFO': 7, 'response_received_count': 2, 'scheduler/dequeued': 2, 'scheduler/dequeued/memory': 2, 'scheduler/enqueued': 2, 'scheduler/enqueued/memory': 2, 'spider_exceptions/AttributeError': 1, 'start_time': datetime.datetime(2019, 10, 15, 6, 35, 10, 741732)} 2019-10-15 15:35:10 [scrapy.core.engine] INFO: Spider closed (finished)

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

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

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

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

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

t_obara

2019/10/15 09:47

エラーの意味は、 post.css('div.post-header.byline.span.date a::attr(href)').extract_first() で得られたオブジェクトがNoneなので、そのオブジェクトにはstripなんて属性名(メソッド)はないですという意味です。 こういう場合、各ステップで各変数がどのような値になっているかを確認していったほうが良いかと思います。特にpost 変数には期待通りの内容が含まれているのかなど。
meg_

2019/10/15 10:22

参考サイトは「リンクの挿入」で記入してください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問