Scrapy学習(三)豆弁図書情報を這い出す
前言 Scrapyラーニング(一)インストール Scrapy学習(二)入門 前の2編の基礎があれば、インターネット上で私たちの興味のある情報を抽出することができます.しばらくはログインのシミュレーションを学んでいないので、豆弁のようにログインする必要のないサイトの内容をつかんでおきます.私の開発環境はWin 7+PyChram+Python 3です.5+MongoDB爬虫類のターゲットは豆弁の日本文学のラベルの下のすべての書籍の基本情報です
プロジェクトの作成
scrapy startproject douban
次に
scrapy genspider book book.douban.com
対応するBookSpiderテンプレートをspiderディレクトリの下で生成
Itemの作成
itemsでpyで必要なデータモデルを作成する
Spiderの作成
豆弁の日本文学のラベルを訪問し、urlの値を
コードに問題があるかどうかをテストします
scrapy crawl book -o items.json
奇妙な発見だitemsjson内にはデータがないので、コンソールのDEBUG情報を後から見ます
2017-02-04 16:15:38 [scrapy.core.engine] INFO: Spider opened2017-02-04 16:15:38 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)2017-02-04 16:15:38 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:60232017-02-04 16:15:39 [scrapy.core.engine] DEBUG: Crawled (403) 2017-02-04 16:15:39 [scrapy.core.engine] DEBUG: Crawled (403)
ページを這い出すときのステータスコードは403です.これは、サーバが爬虫類プログラムを判断し、アクセスを拒否したためです.settingsで
USER_AGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"
もう一度やってみるとitems.jsonは価値がある.しかし、最初のページのデータしかありません.すべてのデータを取得するには、現在のページを登った後、次のページのurlを自動的に取得し、すべてのデータをスクロールする必要があります.spiderを改造しました
そのうち
反爬虫類を突き破る
一般的に、爬虫類の速度が速すぎると.サイトがアクセスを拒否するため、settingsで爬虫類の間隔を設定し、COOKIESをオフにする必要があります.
DOWNLOAD_DELAY = 2COOKIES_ENABLED = False
あるいは、ウェブサイトのマスクを回避するために、異なるブラウザUAまたはIPアドレスを設定することができ、次にUAを変更することを例に挙げることができる.middlewaresでpy,UAをランダムに置換するミドルウェアを作成し,各requestはmiddlewareを通過する.このうち
続く道
プログラムを再実行すると、明らかに速度が速くなった.
MongoDBに保存
次に、データをデータベースに保存して永続化処理を行います(ここではMongoDBを例に挙げて、他のデータベースに保存します).この処理は
pip install pymongo
その他
プロジェクト実行時にコンソールから出力されたDEBUG情報をログファイルに保存します.
LOG_FILE = "logs/book.log"
項目コード住所:豆弁図書爬虫類
プロジェクトの作成
scrapy startproject douban
次に
douban
ディレクトリに移動scrapy genspider book book.douban.com
対応するBookSpiderテンプレートをspiderディレクトリの下で生成
Itemの作成
itemsでpyで必要なデータモデルを作成する
class BookItem(scrapy.Item):
book_name = scrapy.Field()
book_star = scrapy.Field()
book_pl = scrapy.Field()
book_author = scrapy.Field()
book_publish = scrapy.Field()
book_date = scrapy.Field()
book_price = scrapy.Field()
Spiderの作成
豆弁の日本文学のラベルを訪問し、urlの値を
start_urls
に書いた.それからChromeの助けのもとで、1冊の図書がul#subject-list > li.subject-item
であることを見ることができますclass BookSpider(scrapy.Spider):
...
def parse(self, response):
sel = Selector(response)
book_list = sel.css('#subject_list > ul > li')
for book in book_list:
item = BookItem()
item['book_name'] = book.xpath('div[@class="info"]/h2/a/text()').extract()[0].strip()
item['book_star'] = book.xpath("div[@class='info']/div[2]/span[@class='rating_nums']/text()").extract()[
0].strip()
item['book_pl'] = book.xpath("div[@class='info']/div[2]/span[@class='pl']/text()").extract()[0].strip()
pub = book.xpath('div[@class="info"]/div[@class="pub"]/text()').extract()[0].strip().split('/')
item['book_price'] = pub.pop()
item['book_date'] = pub.pop()
item['book_publish'] = pub.pop()
item['book_author'] = '/'.join(pub)
yield item
コードに問題があるかどうかをテストします
scrapy crawl book -o items.json
奇妙な発見だitemsjson内にはデータがないので、コンソールのDEBUG情報を後から見ます
2017-02-04 16:15:38 [scrapy.core.engine] INFO: Spider opened2017-02-04 16:15:38 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)2017-02-04 16:15:38 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:60232017-02-04 16:15:39 [scrapy.core.engine] DEBUG: Crawled (403) 2017-02-04 16:15:39 [scrapy.core.engine] DEBUG: Crawled (403)
ページを這い出すときのステータスコードは403です.これは、サーバが爬虫類プログラムを判断し、アクセスを拒否したためです.settingsで
USER_AGENT
の値を設定し、ブラウザアクセスページに偽装することができます.USER_AGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"
もう一度やってみるとitems.jsonは価値がある.しかし、最初のページのデータしかありません.すべてのデータを取得するには、現在のページを登った後、次のページのurlを自動的に取得し、すべてのデータをスクロールする必要があります.spiderを改造しました
...
def parse(self, response):
sel = Selector(response)
book_list = sel.css('#subject_list > ul > li')
for book in book_list:
item = BookItem()
try:
item['book_name'] = book.xpath('div[@class="info"]/h2/a/text()').extract()[0].strip()
item['book_star'] = book.xpath("div[@class='info']/div[2]/span[@class='rating_nums']/text()").extract()[0].strip()
item['book_pl'] = book.xpath("div[@class='info']/div[2]/span[@class='pl']/text()").extract()[0].strip()
pub = book.xpath('div[@class="info"]/div[@class="pub"]/text()').extract()[0].strip().split('/')
item['book_price'] = pub.pop()
item['book_date'] = pub.pop()
item['book_publish'] = pub.pop()
item['book_author'] = '/'.join(pub)
yield item
except:
pass
nextPage = sel.xpath('//div[@id="subject_list"]/div[@class="paginator"]/span[@class="next"]/a/@href').extract()[0].strip()
if nextPage:
next_url = 'https://book.douban.com'+nextPage
yield scrapy.http.Request(next_url,callback=self.parse)
そのうち
scrapy.http.Request
はparse関数をコールバックしtry...catchは豆弁図書がフォーマットが一致していないからです.問題のあるデータに出会ったら、捨てて使いません.反爬虫類を突き破る
一般的に、爬虫類の速度が速すぎると.サイトがアクセスを拒否するため、settingsで爬虫類の間隔を設定し、COOKIESをオフにする必要があります.
DOWNLOAD_DELAY = 2COOKIES_ENABLED = False
あるいは、ウェブサイトのマスクを回避するために、異なるブラウザUAまたはIPアドレスを設定することができ、次にUAを変更することを例に挙げることができる.middlewaresでpy,UAをランダムに置換するミドルウェアを作成し,各requestはmiddlewareを通過する.このうち
process_request
はNone
を返し、Scrapyは他のmiddlewareに処理を続行します.class RandomUserAgent(object):
def __init__(self,agents):
self.agents = agents
@classmethod
def from_crawler(cls,crawler):
return cls(crawler.settings.getlist('USER_AGENTS'))
def process_request(self,request,spider):
request.headers.setdefault('User-Agent',random.choice(self.agents))
続く道
settings
に設けられているDOWNLOADER_MIDDLEWARES = {
'douban.middlewares.RandomUserAgent': 1,
}
...
USER_AGENTS = [
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
...
]
プログラムを再実行すると、明らかに速度が速くなった.
MongoDBに保存
次に、データをデータベースに保存して永続化処理を行います(ここではMongoDBを例に挙げて、他のデータベースに保存します).この処理は
pipelines
に記載されている.その前に、接続データベースのドライバをインストールします.pip install pymongo
settings
に構成を書きます# MONGODB configure
MONGODB_SERVER = 'localhost'
MONGODB_PORT = 27017
MONGODB_DB = 'douban'
MONGODB_COLLECTION = "book"
class MongoDBPipeline(object):
def __init__(self):
connection = MongoClient(
host=settings['MONGODB_SERVER'],
port=settings['MONGODB_PORT']
)
db = connection[settings['MONGODB_DB']]
self.collection = db[settings['MONGODB_COLLECTION']]
def process_item(self, item, spider):
self.collection.insert(dict(item))
log.msg("Book added to MongoDB database!",
level=log.DEBUG, spider=spider)
return item
その他
プロジェクト実行時にコンソールから出力されたDEBUG情報をログファイルに保存します.
settings
に設定するだけですLOG_FILE = "logs/book.log"
項目コード住所:豆弁図書爬虫類