Friday I/O
でーす!
株式会社ワムウでは、毎週金曜日は 興味がある事柄に取り組み、その成果を何らかの形でアウトプットする日
としておりますよ。
Scrapbookというライブラリを作りました
お仕事で Scrapy
使う機会があったんですけども、HTMLからデータを抽出する部分(ItemLoader)が私の様な貧弱プログラマーには難しすぎたので、もっとシンプルにわかりやすく書けるものを作りました。
ドキュメントの翻訳をgoogle翻訳さんに頼んだんで、文法とかむちゃくちゃだと思います。。(英語わからない)
Repository: https://github.com/odoku/scrapbook
Document: https://scrapbook.readthedocs.org
使い方
PYPIに登録してあります!
pip install scrapbook
README
にも載ってますが、一応こちらにも掲載。
ぱっと見で何やってるかは分かると思います。
--- 注意 ---
記事書いた後に気づいたんですけど、Twitterはクローリングすると激怒する様なのでサンプルの実行は自己責任でお願いします。。
https://twitter.com/ja/tos
--- 注意 ---
from scrapbook import Element, Content
import requests
class Twitter(Content):
username = Element(
xpath='//*[@id="page-container"]/div[2]/div/div'
'/div[1]/div/div/div/div[1]/h2/a/span/b/text()',
)
screen_name = Element(
xpath='//*[@id="page-container"]/div[2]/div/div/'
'div[1]/div/div/div/div[1]/h1/a',
)
response = requests.get('https://twitter.com/odoku')
data = Twitter().parse(response.text)
print(data)
ScrapyでScrapbookを使う
ほぼ上のサンプルとおんなじ。
# -*- coding: utf-8 -*-
import scrapy
from scrapbook import Content, Element
class Tweet(Content):
username = Element(
xpath='.//span[@class="FullNameGroup"]/strong[contains(@class, "fullname")]/text()',
)
text = Element(
xpath='.//p[contains(@class, "tweet-text")]/text()',
)
like = Element(
xpath='.//span[contains(@class, "ProfileTweet-actionCountForPresentation")]/text()',
filter=int,
)
class Twitter(Content):
username = Element(
xpath='//*[@id="page-container"]/div[2]/div/div'
'/div[1]/div/div/div/div[1]/h2/a/span/b/text()',
)
screen_name = Element(
xpath='//*[@id="page-container"]/div[2]/div/div/'
'div[1]/div/div/div/div[1]/h1/a/text()',
)
tweets = Tweet(
xpath='//*[@id="stream-items-id"]/li',
many=True,
)
class ScrapbookSpider(scrapy.Spider):
name = 'scrapbook'
start_urls = ['https://twitter.com/odoku']
def parse(self, response):
return Twitter().parse(response.text)
これをScrapyのItemLoaderで書くと
そもそも ItemLoader
の使い方もよくわかってないので参考にならないかもですけど、こんな感じになると思います。
ロジックとして記述していくので、ぱっと見でわかりづらいなーと個人的には思います。。
# -*- coding: utf-8 -*-
import scrapy
from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst
class Item(scrapy.Item):
username = scrapy.Field(output_processor=TakeFirst())
screen_name = scrapy.Field(output_processor=TakeFirst())
tweets = scrapy.Field()
class ScrapbookSpider(scrapy.Spider):
name = 'scrapy'
start_urls = ['https://twitter.com/odoku']
def parse(self, response):
loader = ItemLoader(item=Item(), response=response)
loader.add_xpath(
'username',
'//*[@id="page-container"]/div[2]/div/div/div[1]/div/div/div/div[1]/h2/a/span/b/text()',
)
loader.add_xpath(
'screen_name',
'//*[@id="page-container"]/div[2]/div/div/div[1]/div/div/div/div[1]/h1/a/text()',
)
loader.add_value('tweets', self.get_tweets(response.xpath('//*[@id="stream-items-id"]/li')))
return loader.load_item()
def get_tweets(self, selector_list):
tweets = []
for selector in selector_list:
tweet = {}
xpath = './/span[@class="FullNameGroup"]/strong[contains(@class, "fullname")]/text()'
tweet['username'] = selector.xpath(xpath).extract_first()
xpath = './/p[contains(@class, "tweet-text")]/text()'
tweet['text'] = selector.xpath(xpath).extract_first()
xpath = './/span[contains(@class, "ProfileTweet-actionCountForPresentation")]/text()'
tweet['like'] = selector.xpath(xpath).extract_first()
if tweet['like']:
tweet['like'] = int(tweet['like'])
tweets.append(tweet)
return tweets
まとめ
特に Scrapy
に依存してるわけではないので、他のライブラリで使うことも出来ますよ。
よかったら使ってみて下さいな。