LinuxのiptablesでTomcatのポートを開放する
VMware上のTomcatにホストマシン(Winsows10)からブラウザでアクセスする為に、Tomcatのポートを開放する。
環境
CentOS 6.6
手順
iptables編集
[root@localhost src]# vi /etc/sysconfig/iptables
追記
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
注意点として、REJECTの行の前に追記する事。
知らずに最終行(COMMIT)の前に追記した時は許可されなかった。
iptables再起動
[root@localhost src]# /etc/rc.d/init.d/iptables restart
アクセスできた
http://192.168.10.111:8080/
scrapyで独自設定値を設定ファイルに追加して利用する
scrapyで独自設定値を設定ファイルに追加して利用する方法。
setting.pyに追記
TESTKEY = HOGEHOGE
こんな感じで利用
from scrapy.conf import settings ~~~ value = settings.get("TESTKEY")
int型、boolean型、float型の指定も出来るみたい。
settings.getint("TESTKEY") settings.getfloat("TESTKEY") settings.getbool("TESTKEY")
第2引数でデフォルト値も設定できるみたい
value = settings.get("TESTKEY", "DEFAULT")
dic型も利用できる
COOKIES = { "key1": "value21", "key2": "value2" }
value = settings.get("COOKIES")
scrapyでcookieを設定してクロールする
spidersパッケージ内のクロール処理メインのモジュールで以下のようにmake_requests_from_urlを定義してその中でcookieセット処理を実装する事でログインが必要なサイトでもクロールできた。
class ExampleSpider(CrawlSpider): ~~~ def make_requests_from_url(self, url): request = super(ExampleSpider, self).make_requests_from_url(url) request.cookies['test_key'] = 'value1' request.cookies['test_key2'] = 'value2' return request
注意点としてCrawlSpiderの継承クラスである事。
scrapy.Spiderの継承クラスの場合は異なるっぽい事をどっかで見かけた。(未検証)
Python製のクローラー「scrapy」の利用方法や初期設定など纏め
Python製のクローラーフレームワークscrapyを使用してクローラーを構築する。
目次
環境
Windows10 64bit Python for Windows(3.5.1) Eclipse4.6 PyDev(Eclipseプラグイン) Cygwin
やりたい事
どこかのサイトのクローラーを1時間で実装
今回は参考サイトと同じグノシーを対象とする。
手順
クローラプロジェクトの雛形作成
$ scrapy startproject gunosy_crawl
スパイダーの作成
scrapy genspiderの第1引数はPythonファイル名、第2引数はクロール対象サイトのドメイン
$ cd gunosy_crawl/ $ scrapy genspider gunosy gunosy.com
起点URLを定義
/gunosy_crawl/gunosy_crawl/spiders/gunosy.py
- start_urls
クロール起点URLを定義、タプルで複数指定も可能。
- allowed_domains
クロール許可ドメイン、配列で複数指定可能
class GunosySpider(scrapy.Spider): name = "gunosy" allowed_domains = ["gunosy.com"] start_urls = ( 'https://gunosy.com/' )
アイテムクラスを実装
クロール結果を保存するアイテムクラスを実装します。
gunosy_crawl/gunosy_crawl/items.py
class GunosyCrawlItem(scrapy.Item): title = scrapy.Field() url = scrapy.Field() text = scrapy.Field()
今回はタイトルとURLと本文を設定する。
パース処理実装
今回はグノシーのニュース記事ページから記事本文を取得対象とする。
例としてこのようなページ
https://gunosy.com/articles/Rol5u
このページのソースをブラウザで確認して記事本文エリアのタグを取得する。
見た感じこれ
<div class="article gtm-click" data-gtm="article_article">
Scrapy Shellによるデバッグ
scrapyのデバッグ機能を使って当該ページのパース処理を確認
$ scrapy shell https://gunosy.com/articles/Rol5u
実行するとiPythonが起動する。
タグに対応したパース処理実行
response.xpath('//div[@class="article gtm-click"]/*/text()').extract()
テキスト取得された。
当方はcygwinで実行している為、日本語が表示されていないが恐らく問題無し。
配列データとなってるのはdivタグ内のpタグ分が存在している為と思われる。
In [1]: response.xpath('//div[@class="article gtm-click"]/*/text()').extract() Out[1]: ['929', '', '4', '4', '4,000iOSAndroidMacWindows342', '', '3', '13,5003', '22006Discover WeeklyRelease Reader', '3Spotify Free', '3', '']
パース処理の実装
/gunosy_crawl/gunosy_crawl/spiders/gunosy.py
def parse(self, response): article_text = response.xpath('//div[@class="article gtm-click"]/*/text()').extract() #取得対象のページのみヒットするはず if article_text is not None : article = GunosyCrawlItem() article['title'] = response.selector.xpath('//title/text()') article['url'] = response.urljoin article['text'] = article_text yield article else: print("not get text data : {0}".format(response.urljoin)) linklist = response.xpath('//a/@href').extract() for link in linklist: yield scrapy.Request(link, callback=self.parse)
Parse コマンドによるデバッグ
scrapy parse --spider=gunosy https://gunosy.com/articles/Rol5u
以下のように、Scraped ItemsとRequestsの結果を見て、スクレイピング結果とクロールURLの取得が出来ている事を確認します。
# Scraped Items ------------------------------------------------------------ [{'text': '929 ' ' ' '4 ' '4 ' '4,000iOSAndroidMacWindows342 ' ' 3 ' '13,5003 ' '22006Discover ' 'WeeklyRelease ' 'Reader ' '3Spotify ' 'Free ' '3 ' '', 'title': '... - ', 'url': 'https://gunosy.com/articles/Rol5u'}] # Requests ----------------------------------------------------------------- [<GET https://gunosy.com/>, <GET https://gunosy.com/users/sign_in>, <GET https://gunosy.com/sitemap>,
以下のようなエラーが出た場合、yield scrapy.Requestで返してるURLが不正という事らしいです。
ValueError: Missing scheme in request url: //gunosy.co.jp/
対策として以下のようにurljoinメソッドを使って整形しましょう
yield scrapy.Request(response.urljoin(link), callback=self.parse)
保存先指定
gunosy_crawl/gunosy_crawl/settings.py
# シードURLのファイル形式 FEED_FORMAT = 'csv' # シードURLの保存先 FEED_URI = 'file:///tmp/export.csv'
2016/9/5時点では、jsonとjsonlinesは日本語ユニコードデコードに未対応なので使いたい場合はカスタマイズが必要らしい。
Python: Scrapy と BeautifulSoup4 を使った快適 Web スクレイピング | CUBE SUGAR STORAGE
その他設定
gunosy_crawl/gunosy_crawl/settings.py
#ユーザーエージェント USER_AGENT = 'gunosy_crawl (+http://www.yourdomain.com)' #True = Webサイトのrobots.txtに従う ROBOTSTXT_OBEY = True #Webページのダウンロード間隔 DOWNLOAD_DELAY = 2 #ログ出力先 LOG_FILE = '/tmp/scrapy.log'
色々やりたい時
スクレイピングURLルールを指定したい場合
まず、スーパークラスを変更
class GunosySpider(scrapy.Spider):
↓変更↓
class GunosySpider(CrawlSpider):
スクレイピング対象URLとか指定する
# スクレイピングを開始するURL、複数指定可 start_urls = ['https://gunosy.com/'] # スクレイピング対象のパスパターン、ドメイン以下のURLに関して正規表現で指定します allow_list = ['/articles/'] # スクレイピング対象外パスパターン、ドメイン以下のURLに関して正規表現で指定します deny_list = ['/categories/', '/ranking/'] rules = ( # スクレイピングするURLのルールを指定 Rule(LinkExtractor( allow=allow_list, deny=deny_list), callback='parse_item'), # spiderがたどるURLを指定 Rule(LinkExtractor(), follow=True), )
上記callbackで指定した関数を実装。
元々あったparse関数は削除。
※parse関数がある場合はparse関数が優先して実行されるので注意
def parse_item(self, response): article_text = response.xpath('//div[@class="article gtm-click"]/*/text()').extract() article = GunosyCrawlItem() article['url'] = response.urljoin('') article['title'] = response.selector.xpath('//title/text()').extract()[0].replace('\n','') article['text'] = ' '.join(article_text).replace('\n','') print("article_text2 : {0}".format(article)) #クロール結果を出力 yield article #ページ内の全てのaタグリンクをクロール linklist = response.xpath('//a/@href').extract() for link in linklist: # 次のクロール対象を渡す yield scrapy.Request(response.urljoin(link), callback=self.parse)
日本語Unicodeデコードした文字列でjson形式で出力
scrapyでは出力フォーマットの形式をexporterで拡張できるらしい。
独自モジュールを実装して日本語エスケープ文字列を出力前にデコードする。
gunosy_crawl/gunosy_crawl/exporters.py
を新規作成
#!/usr/bin/env python # -*- coding: utf-8 -*- from scrapy.contrib.exporter import JsonLinesItemExporter class NonEscapeJsonLinesItemExporter(JsonLinesItemExporter): def __init__(self, filepath, **kwargs): super(NonEscapeJsonLinesItemExporter, self).__init__( filepath, ensure_ascii=False )
設定モジュールも編集
gunosy_crawl/gunosy_crawl/settings.py
FEED_FORMAT = 'jsonlines' FEED_URI = 'file:///tmp/export.json' FEED_EXPORTERS = { 'jsonlines': 'gunosy_crawl.exporters.NonEscapeJsonLinesItemExporter', }
jsonlinesというのはJSONを行形式にしたものらしく、その形式を指定。
FEED_EXPORTERSという変数で拡張したexporterを指定する。
ここでjsonlinesを指定して、jsonlinesの時はこのexporterを使用するという意味らしい。
ログ出力
バージョン1.0より前ではscrapy.log.msgメソッドを使用していたようだけど、現在はビルトインのloggingを利用推奨みたい。
import logging logging.warning("This is a warning")
実行
$ scrapy crawl gunosy
取得結果を確認
less /cygdrive/d/tmp/export.csv
おわりに
- scrapy1.0でpython3に対応してからは日本語の解説ページも増えてきてるみたい。
- 公式のドキュメントを読み漁ればもっと色々できそう。
- 学習コストもそこまで高くない気がするので、汎用的な処理を実装しておきサイト個別の処理を設定ファイルとかに纏めておけば新たなサイトのクローラーを構築するのも直ぐにできそう。
- DBとの連携も出来るらしいので今後調査
- プロセスが落ちた後、新たにプロセスを立ち上げると一度クロール済みのページも再度取得済みなるらしいので対策が無いか調査する
- Scrapy Cloudというサービスがあるらしいので要調査
Windowsで最強のPython開発環境を構築するまで【都度更新】
WindowsでのPython開発環境。
試行錯誤の上ようやく落ち着いてきたので纏め。
随時更新する。
全然最強じゃ無いじゃん、とかのツッコミは無しで。
目次
環境
Windows10 64bit Python for Windows(3.5.1) Eclipse4.6 PyDev(Eclipseプラグイン) Cygwin VMware
希望する開発環境
Python for Windows 64bit
Windowsなのでもちろんこれ。
cygwinでの作業も考えてcygwin内のpythonを使用していた時期もあったがライブラリ周りで躓く事が多かった為、Windows版の利用に落ち着いた。
PyDev(Eclipseプラグイン)
IDEはEclipseのプラグインPyDevを利用。
コード補完とブレークポイントによるデバッグも可能。
色々試したがイマイチ使いずらかったIDE
SublimeText2
使いづらいという訳では無いけど何かもの足りなかった。
IDEに乗り換えたい気持ちが日に日に募ってきたので使うのをやめた。
導入方法例↓
PyCharm
- コード補完の挙動が怪しかった(保管されないコードがある等)
- 日本語に対応しておらずたまにメニュー操作でハマる
ネットを見る限り使用者は多そう、知り合いのエンジニアも使っていた。
恐らく自分が知識低いだけと思うけど、使いにくさを感じた。
Visual Studio Express 2015 Python Tools
- デバッグもコード補完も出来てまぁまぁ快適
- 評価版だったようで、30日過ぎたら使用できなくなった
- VisualStudiという事でソリューションディレクトリや専用ファイルが作成されたりするのが何か嫌
- コード補完がたまに怪しい
個人的にはまあまあ使い勝手は良かったので今後ずっとこれを使ってく予定だったけど試用期間過ぎたら使えなくなったので使うのをやめた。
恐らく無償版はあると思うけど調べてない。
コード補完の設定でハマった時のメモ↓
Visual Studio Express 2015 Python Toolsでコード補完が効かない時の対処方法 - ボールを蹴りたいシステムエンジニア
Cygwin
ローカル環境でも出来る限りLinuxに近い形で動作確認を行う為に利用。
PyDev上でのpythonの実行動作確認は行えるが、結局本番環境はLinuxなので。
人によっては不要かもしれないが、自分はコマンド操作が楽で好きなので利用。
注意点としてcywinでのpython実行はcygwinのpythonでは無くwindowsのpythonが実行されるようPATHの設定やalias設定を行う事。
自分の環境では以下のようにcygwinの.bashrcに記述して利用している。
alias python-windows='/cygdrive/c/Python3.5/python.exe' alias pip-windows='/cygdrive/c/Python3.5/Scripts/pip3.5.exe'
サクラエディタとかcygwinから使いたかったら適宜設定する
function sakura() { cygstart /cygdrive/c/Program\ Files\ \(x86\)/sakura/sakura.exe `cygpath -aw $*` & }
VMware
開発環境というよりは学習や動作検証の為に利用。
機械学習ライブラリ周りの学習の為にはやはりLinux環境での確認が色々と捗る。
PyDevでの実装コードとVMwareのソース連携はcygwinからscp経由で連携する。
Windowsでのpython開発環境で気を付ける事
ライブラリのインストール
後述する機械学習ライブラリも該当するが、pipを利用してのライブラリインストールは(gccビルド等)本来Linxu環境での動作が想定されている為、windows環境でインストールをしても正常に動作しない事がある。
非公式ながら有志の方が作成したWindows版のライブラリをWheelファイルからインストールする。
当該ライブラリ名で検索して環境・バージョンに適したファイルをダウンロードする。
Python Extension Packages for Windows - Christoph Gohlke
Wheelファイルからのインストールでも少しハマったのでその時の記事↓
【解決】続・Windows10のpython3.5でlxmlをインストールしようとしたらハマったのでメモ - ボールを蹴りたいシステムエンジニア
Mecab
単純にMecabを使うだけなら公式のインストーラーからの導入で問題無く使えるんだけど、pythonで利用する為のmecab-pythonを導入がかなり面倒くさい。
MeCabはWindowsにおいてはVSを使ってコンパイルするようにソースコードが作られている為VSのインストールが必要。
更に公式のWindows版Mecabが32ビット版しか無い為色々とソースの修正が必要となる事等があり、かなりハマった。
何とか問題無く利用できるようになったけど何度挫折しようとした事か。
その時の記事↓
WindowsのPythonでMecabを実行する(+Cygwinでも実行する) - ボールを蹴りたいシステムエンジニア
かなりハマった。