このドキュメントは、ぴょこりんクラスタ Advent Calendar 2015のために書いたものであり、 、これに引き続き、神のシステムに挑みます。言うまでもないですが、神のシステムに挑む者とは彼女のことを指します。
通常のアレだと1週間分のツイートしか検索できないけどブラウザ上ではもっと古いツイートが見つかる。ってことは普通にスクレイピングすれば古いツイート取れるんじゃないの?
from requests_oauthlib import OAuth1Session
CKey,CSecret, AToken, ASecret=open('./TWOauth','rb').read().strip().split('\n')
knatsuno=OAuth1Session(CKey,CSecret, AToken, ASecret)
from bs4 import BeautifulSoup as bs
import bs4
results=[]
query=u'サナララ'
def strongstrip(s):
if type(s)!=bs4.element.NavigableString and type(s)!=str:
if len(s.contents)==0: s=''
else:
s= s.contents[0]
s=strongstrip(s)
return s
req2 = knatsuno.get(u'https://twitter.com/search?f=tweets&vertical=default&q=%s&src=typd'%query)
t=bs(req2.content, "lxml").findAll("div", { "class" : "content" })
for i in range(10):
for text in t[1:]:
results.append([text.findAll('a')[0]['href'].strip('/'),text.findAll('strong')[0].contents[0], \
text.findAll('a')[1]['title'], ''.join([strongstrip(i) for i in text.findAll('p')[0]]), \
text.findAll('a')[1]['href'].split('/')[-1]])
req3= knatsuno.get(u'https://twitter.com/search?f=tweets&q=%s max_id%%3A%s&src=typd'%(query,str(int(results[-1][-1])-1)))
t=bs(req3.content, "lxml").findAll("div", { "class" : "content" })
if len(t)==1:
break
print '取得できたツイートは%d個' % len(results)
print '一番ふるいのは、'
for i in results[-1][:len(results[-1])]:
print i
取得できたツイートは77個 一番ふるいのは、 flat_ps flat.ps 3:32 - 2015年12月5日 サナララR たのむ 673102626423091200
だめでしたー。もっと古いのがとりたいんだよ僕は。というわけで次の一手を考えなきゃいけないんだ。と言うわけで次の一手、Seleniumをご紹介。これが石の名前とかだとsanararity高めで良かったんですが残念ながらミネラル的なヤツ。
Seleniumはウェブブラウザの操作自動化のためのツールです。Web開発者向けのテスト用途に使われてるやつだそうです。と言うわけでpythonからウェブブラウザ起動、検索クエリを投げ、5回ほど下にスクロールさせて、そのあとそのページをスクレイピングしてみましょうか。うまくいけばそこそこ古めなツイートが取れてるはず。以下のスクリプトでは古いの5つをピックアップしてprintしています。
from selenium import webdriver
import time
fox =webdriver.Firefox()
fox.get(u'https://twitter.com/search?f=tweets&vertical=default&q=%s&src=typd'%query)
time.sleep(3)
for i in range(5):
fox.execute_script('window.scrollTo(0, 10000000)') #下にスクロールしてるだけです。
time.sleep(3)
data = fox.page_source.encode('utf-8')
#これ以降はスクレイピング+表示なので前野と一緒
from bs4 import BeautifulSoup as bs
import bs4
def strongstrip(s):
if type(s)!=bs4.element.NavigableString and type(s)!=str:
if len(s.contents)==0: s=''
else:
s= s.contents[0]
s=strongstrip(s)
return s
t=bs(data, "lxml").findAll("div", { "class" : "content" })
for text in t[-1:-6:-1]:
print text.findAll('a')[0]['href'].strip('/')
print text.findAll('strong')[0].contents[0]
print text.findAll('a')[1]['title']
print ''.join([strongstrip(i) for i in text.findAll('p')[0]])
print ''
ergserifu_bot エロゲセリフbot 10:34 AM - 29 Nov 2015 折角,こんなチャンスだったのに,ここで雨に濡れて,絵とか描いてて…(サナララ/矢神由梨子) yamato1428 やまと 5:25 PM - 29 Nov 2015 @ サナララときいて思わずコメント うめ先生の親戚の絵はかわいいし、シナリオも無駄なものがない一種の最高傑作ですね kinotanu Cloverキノたぬ 7:18 PM - 29 Nov 2015 サナララRやるのは夜にするか capp365 pyoriko.ex_ 11:17 PM - 29 Nov 2015 サナララは更に学びが多かった。 HomuHoooomu やはり俺の社会人生活は間違っているP 12:36 AM - 30 Nov 2015 @ サナララ初プレイはおいくつの時だったんですか!?(真剣
どう見てもNovemberです本当にありがとうございました!!!!!!!!
これをもっと下にスクロールしまくればガンガン古いツイートが漁れそうです。それにしてもサナララは本当に学びが多いですね。サナララがなければ僕がSeleniumと出会うことは無かったはず。あ、一生に一度のチャンスをそんなアレで消費しちゃうのはもちろんお断りです。
さて、上述のスクリプトについて問題点を挙げるとすれば、
あたりでしょうか。1つ目に関しては、前回やったmax_idであるID以前を対象とした検索クエリを定期的に投げなおすことによって解決できそうです。2つ目に関してはブラウザ画面の無いブラウザを使えばええやんってことでPhantomJSを使うことにより解決出来そうです。・・・っと思ったのですがPhantomJSダメでした(こんなのがあった)。apt-getで入れたら1.9が入ったので、新しめなバージョン入れると何とかなりそうかも。気が向いたらこれもやってみようかなと。
と言うわけで神のシステムの限界(一週間)を超えることが出来ました。サナララっぽい記事が書けた気がして、すごい満足しています。それにしてもSelenium素晴らしいですね。クローリング、スクレイピングに使えるのはもちろんですが、社内システムのクソみたいなユーザインターフェースへの対策として、必要な情報を用意しておけばそのクソ冗長なフォームに全ての項目を自動入力してくれるスクリプトなんてのもかけるかもしれませんね!