#!/usr/bin/env python # coding: utf-8 # # サナララツイート自動収集の基礎的検討(2) # # このドキュメントは、[ぴょこりんクラスタ Advent Calendar 2015](http://www.adventar.org/calendars/960)のために書いたものであり、 # 、[これ](http://nbviewer.ipython.org/github/capp365/mynote/blob/master/advent2.ipynb)に引き続き、神のシステムに挑みます。言うまでもないですが、神のシステムに挑む者とは[彼女](https://www.google.com/search?q=%E5%8D%97%E6%96%B9%E3%81%B2%E3%81%8B%E3%82%8B)のことを指します。 # # ## 前回までのおさらい # # 通常のアレだと1週間分のツイートしか検索できないけどブラウザ上ではもっと古いツイートが見つかる。ってことは普通にスクレイピングすれば古いツイート取れるんじゃないの? # In[2]: 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 # だめでしたー。もっと古いのがとりたいんだよ僕は。というわけで次の一手を考えなきゃいけないんだ。と言うわけで次の一手、Seleniumをご紹介。これが石の名前とかだとsanararity高めで良かったんですが残念ながらミネラル的なヤツ。 # # # ## Selenium最高 # [Selenium](http://www.seleniumhq.org/)はウェブブラウザの操作自動化のためのツールです。Web開発者向けのテスト用途に使われてるやつだそうです。と言うわけでpythonからウェブブラウザ起動、検索クエリを投げ、5回ほど下にスクロールさせて、そのあとそのページをスクレイピングしてみましょうか。うまくいけばそこそこ古めなツイートが取れてるはず。以下のスクリプトでは古いの5つをピックアップしてprintしています。 # In[11]: 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 '' # どう見てもNovemberです本当にありがとうございました!!!!!!!! # # # これをもっと下にスクロールしまくればガンガン古いツイートが漁れそうです。それにしてもサナララは本当に学びが多いですね。サナララがなければ僕がSeleniumと出会うことは無かったはず。あ、一生に一度のチャンスをそんなアレで消費しちゃうのはもちろんお断りです。 # # さて、上述のスクリプトについて問題点を挙げるとすれば、 # # - 下にスクロールしすぎると表示してるページがめっちゃでかくなり、下手すると凍る(夏野こおり!!) # - Firefox起動するのがうざい # # #  あたりでしょうか。1つ目に関しては、[前回](http://nbviewer.ipython.org/github/capp365/mynote/blob/master/advent2.ipynb)やったmax_idであるID以前を対象とした検索クエリを定期的に投げなおすことによって解決できそうです。2つ目に関してはブラウザ画面の無いブラウザを使えばええやんってことで[PhantomJS](http://phantomjs.org/)を使うことにより解決出来そうです。・・・っと思ったのですがPhantomJSダメでした([こんなのがあった](http://stackoverflow.com/questions/26991998/selenium-phantomjs-does-not-work-for-twitter-com))。apt-getで入れたら1.9が入ったので、新しめなバージョン入れると何とかなりそうかも。気が向いたらこれもやってみようかなと。 # # ## まとめ # #  と言うわけで神のシステムの限界(一週間)を超えることが出来ました。サナララっぽい記事が書けた気がして、すごい満足しています。それにしてもSelenium素晴らしいですね。クローリング、スクレイピングに使えるのはもちろんですが、社内システムのクソみたいなユーザインターフェースへの対策として、必要な情報を用意しておけばそのクソ冗長なフォームに全ての項目を自動入力してくれるスクリプトなんてのもかけるかもしれませんね!