前提・実現したいこと
Yahooニュースの主要リストタブの1件目の情報を取得しようとしています。
※主要リストタブの1件目が動画ありのものだと失敗しますが、対象は動画なしのものです。
取得したいのは下記の5つ、
①タイトル 「title」、
②カテゴリ 「category」、
③タイトルのURL 「url」、
④③のURL先の(リンク付きの)見出し文 「summary」、
⑤④のリンク先の『○○/○○(曜日)○○:○○配信』という文字列 「haisintext」
です。
$ scrapy crawl ynews -o news.json 1> one.txt 2> two.txt
①〜④は問題なくファイルに出力されているのですが、⑤には「日時配信」の文字列ではなく、
その文字列があるページのURLが出力されます。
'haisinlink': '〜'ではなく、'haisintext': '4/29(日) 18:02配信'としたいです。
{'category': 'スポーツ',
'haisinlink': 'https://headlines.yahoo.co.jp/hl?a=20180429-00000132-dal-base',
'summary': '巨人が逆転で2年ぶり7連勝、代打・阿部の今季初安打で同点「最高です!」も今季初',
'title': 'G7連勝 阿部「やっと打てた」',
'url': 'https://news.yahoo.co.jp/pickup/6280827'}
parseメソッドからgetArticleメソッドへのcallback(summary取得)は問題ないのですが、
getArticleメソッドからgetTextメソッドへのcallback(haisintext取得希望)のやり方が分かりません。
どのように記述すれば良いのでしょうか。ご教示お願いいたします。
settings.py
ROBOTSTXT_OBEY = True
DOWNLOAD_DELAY = 3
HTTPCACHE_ENABLED = False
FEED_EXPORT_ENCODING = 'utf-8'
発生している問題・エラーメッセージ
2018-04-29 20:48:15 [scrapy.utils.log] INFO: Scrapy 1.5.0 started (bot: nobel_winners)
2018-04-29 20:48:15 [scrapy.utils.log] INFO: Versions: lxml 4.1.1.0, libxml2 2.9.7, cssselect 1.0.3, parsel 1.4.0, w3lib 1.19.0, Twisted 17.9.0, Python 3.6.4 (default, Feb 10 2018, 20:17:51) - [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)], pyOpenSSL 17.5.0 (OpenSSL 1.1.0h 27 Mar 2018), cryptography 2.2.2, Platform Darwin-16.7.0-x86_64-i386-64bit
2018-04-29 20:48:15 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'nobel_winners', 'DEPTH_LIMIT': 5, 'DOWNLOAD_DELAY': 3, 'FEED_EXPORT_ENCODING': 'utf-8', 'FEED_FORMAT': 'json', 'FEED_URI': 'news.json', 'NEWSPIDER_MODULE': 'nobel_winners.spiders', 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['nobel_winners.spiders']}
2018-04-29 20:48:15 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
'scrapy.extensions.telnet.TelnetConsole',
'scrapy.extensions.memusage.MemoryUsage',
'scrapy.extensions.feedexport.FeedExporter',
'scrapy.extensions.logstats.LogStats']
2018-04-29 20:48:15 [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']
2018-04-29 20:48:15 [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']
2018-04-29 20:48:15 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2018-04-29 20:48:15 [scrapy.core.engine] INFO: Spider opened
2018-04-29 20:48:15 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2018-04-29 20:48:15 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6024
2018-04-29 20:48:15 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://news.yahoo.co.jp/robots.txt> (referer: None)
2018-04-29 20:48:19 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://news.yahoo.co.jp/list> (referer: None)
2018-04-29 20:48:23 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://news.yahoo.co.jp/pickup/6280827> (referer: https://news.yahoo.co.jp/list)
2018-04-29 20:48:23 [scrapy.core.scraper] DEBUG: Scraped from <200 https://news.yahoo.co.jp/pickup/6280827>
{'category': 'スポーツ',
'haisinlink': 'https://headlines.yahoo.co.jp/hl?a=20180429-00000132-dal-base',
'summary': '巨人が逆転で2年ぶり7連勝、代打・阿部の今季初安打で同点「最高です!」も今季初',
'title': 'G7連勝 阿部「やっと打てた」',
'url': 'https://news.yahoo.co.jp/pickup/6280827'}
2018-04-29 20:48:23 [scrapy.core.engine] INFO: Closing spider (finished)
2018-04-29 20:48:23 [scrapy.extensions.feedexport] INFO: Stored json feed (1 items) in: news.json
2018-04-29 20:48:23 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 759,
'downloader/request_count': 3,
'downloader/request_method_count/GET': 3,
'downloader/response_bytes': 22206,
'downloader/response_count': 3,
'downloader/response_status_count/200': 3,
'finish_reason': 'finished',
'finish_time': datetime.datetime(2018, 4, 29, 11, 48, 23, 584196),
'item_scraped_count': 1,
'log_count/DEBUG': 5,
'log_count/INFO': 8,
'memusage/max': 53182464,
'memusage/startup': 53182464,
'request_depth_max': 1,
'response_received_count': 3,
'scheduler/dequeued': 2,
'scheduler/dequeued/memory': 2,
'scheduler/enqueued': 2,
'scheduler/enqueued/memory': 2,
'start_time': datetime.datetime(2018, 4, 29, 11, 48, 15, 328173)}
2018-04-29 20:48:23 [scrapy.core.engine] INFO: Spider closed (finished)
ファイル出力結果 (news.json)
[
{"title": "G7連勝 阿部「やっと打てた」", "category": "スポーツ", "url": "https://news.yahoo.co.jp/pickup/6280827", "summary": "巨人が逆転で2年ぶり7連勝、代打・阿部の今季初安打で同点「最高です!」も今季初", "haisinlink": "https://headlines.yahoo.co.jp/hl?a=20180429-00000132-dal-base"}
]
該当のソースコード
import scrapy
class NewsItem(scrapy.Item):
title = scrapy.Field()
category = scrapy.Field()
url = scrapy.Field()
summary = scrapy.Field()
haisintext = scrapy.Field()
haisinlink = scrapy.Field()
class YnewsSpider(scrapy.Spider):
name = "ynews"
start_urls = ['https://news.yahoo.co.jp/list']
def parse(self, response):
for selectElements in response.xpath('//*[@id="main"]/div[1]/div[1]/div[4]/ul'):
item = NewsItem() # 先頭の記事が動画ありだと失敗するので、下3行分の.//li[1]を[2]とかにずらしてやり過ごす
item['title'] = selectElements.xpath('.//li[1]/a/dl/dt/text()').extract_first()
item['category'] = selectElements.xpath('.//li[1]/a/dl/dd/text()').extract_first()
item['url'] = selectElements.xpath('.//li[1]/a/@href').extract_first()
request = scrapy.Request(item['url'], callback = self.getArticle, dont_filter = True)
request.meta['item'] = item
yield request
def getArticle(self, response):
item = response.meta['item']
item['summary'] = response.xpath('//*[@id="link"]/text()').extract_first()
item['haisinlink'] = response.xpath('//*[@id="link"]/@href').extract_first()
request = scrapy.Request(item['haisinlink'], callback = self.getText, dont_filter = True)
yield item
def getText(self, response):
item = response.meta['item']
item['haisintext'] = response.xpath('//*[@id="ym_newsarticle"]/div[1]/div/p[1]/text()').extract_first()
yield item
『○○/○○(曜日)○○:○○配信』別の方法で取得
しましたが、結局二つ目callback呼び出しは解決出来ないまま...
import scrapy
import urllib, lxml
class NewsItem(scrapy.Item):
title = scrapy.Field()
category = scrapy.Field()
url = scrapy.Field()
summary = scrapy.Field()
haisintext = scrapy.Field()
# haisinlink = scrapy.Field()
class YnewsSpider(scrapy.Spider):
name = "ynews"
start_urls = ['https://news.yahoo.co.jp/list']
def parse(self, response):
for selectElements in response.xpath('//*[@id="main"]/div[1]/div[1]/div[4]/ul'):
item = NewsItem() # 先頭の記事が動画ありだと失敗するので、下3行分の.//li[1]を[2]とかにずらしてやり過ごす
item['title'] = selectElements.xpath('.//li[3]/a/dl/dt/text()').extract_first()
item['category'] = selectElements.xpath('.//li[3]/a/dl/dd/text()').extract_first()
item['url'] = selectElements.xpath('.//li[3]/a/@href').extract_first()
request = scrapy.Request(item['url'], callback = self.getArticle, dont_filter = True)
request.meta['item'] = item
yield request
def getArticle(self, response):
item = response.meta['item']
item['summary'] = response.xpath('//*[@id="link"]/text()').extract_first()
haisinlink = response.xpath('//*[@id="link"]/@href').extract_first()
target_url = haisinlink
res = urllib.request.urlopen(target_url)
dom = lxml.html.fromstring(res.read())
haisin_txt = dom.xpath('//*[@id="ym_newsarticle"]/div[1]/div/p[1]/text()')
result = haisin_txt[0].strip()
item['haisintext'] = result
yield item
補足情報(FW/ツールのバージョンなど)
Python 3.6.4
scrapy 1.5.0
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
{'category': 'スポーツ',
'haisintext': '5/3(木) 9:34 掲載',
'summary': '白星無し3連敗…ダルビッシュに地元ファンからブーイング',
'title': 'ダル3敗目 地元でブーイング',
'url': 'https://news.yahoo.co.jp/pickup/6281189'}
このようなものを取得するのが目的でしょうか。
でしたら、haisintextにあたるもののxpathが
//*[@id="main"]/div[@class="mainBox"]/div[@class="topicsDetail"]/div[@class="topicsHead"]/div[@class="topicsName"/span[@class="date"]
となっていますので、getArticle
中でhaisintext取得を行えばよいかと思います。例えば下記のように
item['haisintext'] = response.xpath('//div[@class="topicsName"]/span[@class="date"]/text()').extract_first()
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.32%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2018/05/03 15:15
分かり難くて申し訳ありません。目的の文字列を取得するページの場所ですが、頂いた回答の例で挙げますと、
’url’: ‘http://news.yahoo.co.jp/pickup/6281189’ のページ内の
’summary’: ‘白星〜(略)〜ブーイング’ をクリックしたリンク先のページ内にある、
xpathが『//*[@id=“ym_newsarticle”]/div[1]/div/p[1]/text()』の
『○○/○○(曜日)○○:○○配信』という文字列になります。
こちらを getArticle()内のcallback=self.getText()を使って取得する(getTextにデータを渡す)方法が質問の趣旨となります。
2018/05/10 10:30
```
def getArticle(self, response):
item = response.meta['item']
item['summary'] = response.xpath('//*[@id="link"]/text()').extract_first()
item['haisinlink'] = response.xpath('//*[@id="link"]/@href').extract_first()
request = scrapy.Request(item['haisinlink'], callback = self.getText, dont_filter = True)
yield item
```
ここの最後を
```
request = scrapy.Request(item['haisinlink'], callback = self.getText, dont_filter = True)
request.meta["item"]=item
yield request
```
とするのではダメなんでしょうか
2018/05/12 00:03