概述
在前面兩篇(爬蟲學(xué)習(xí)之基于Scrapy的網(wǎng)絡(luò)爬蟲和爬蟲學(xué)習(xí)之簡單的網(wǎng)絡(luò)爬蟲)文章中我們通過兩個(gè)實(shí)際的案例狮含,采用不同的方式進(jìn)行了內(nèi)容提取。我們對網(wǎng)絡(luò)爬蟲有了一個(gè)比較初級的認(rèn)識旷赖,只要發(fā)起請求獲取響應(yīng)的網(wǎng)頁內(nèi)容舟陆,然后對內(nèi)容進(jìn)行格式化存儲。很多時(shí)候我們抓取到的內(nèi)容可能會(huì)發(fā)生重復(fù)勉痴,也有可能是需要計(jì)算或者組織過的全新的內(nèi)容甚至是需要登錄后才能訪問的內(nèi)容秒际, 那么這一篇我們來學(xué)習(xí)一下Scrapy的Item部分以及了解如何使用Scrapy來進(jìn)行自動(dòng)登錄悬赏。
起步
首先我們使用Scrapy的命令行創(chuàng)建一個(gè)新的項(xiàng)目
scrapy startproject douban
運(yùn)行后,我們就有了下面這樣的目錄結(jié)構(gòu)
+ douban # 根目錄
|- douban # Python的項(xiàng)目目錄
|- spiders # 爬蟲Spider部分娄徊,用于提取網(wǎng)頁內(nèi)容
|- __init__.py
|- __init__.py
|- items.py # 爬蟲item闽颇, 用于定義數(shù)據(jù)結(jié)構(gòu)
|- pipelines.py # 爬蟲pipeline,用于處理提取的結(jié)構(gòu)寄锐,比如清洗數(shù)據(jù)兵多、去重等
|- settings.py # Scrapy框架參數(shù)項(xiàng)目參數(shù)設(shè)置
|- scrapy.cfg # 爬蟲部署相關(guān)設(shè)置
Scrapy為我們生成了已經(jīng)組織好的目錄結(jié)構(gòu)尖啡,上面的注釋部分解釋了每個(gè)文件及目錄的作用。
建立目標(biāo)
本篇我們來建立兩個(gè)目標(biāo)剩膘,這兩個(gè)目標(biāo)都是基于豆瓣網(wǎng):
目標(biāo)一:抓取豆瓣TOP250的圖書信息并保存成csv文件
目標(biāo)二:抓取我的第一頁豆郵標(biāo)題(需要登錄)衅斩,并保存成csv文件
分析目標(biāo)一
目標(biāo)一是豆瓣的TOP250圖書信息,首先我們進(jìn)入到TOP250的列表(https://book.douban.com/top250) 怠褐,我用圖示圈出我們這次要爬取的內(nèi)容畏梆,具體請看圖示:
從圖上的框線中我們主要圈出了書名、價(jià)格奈懒、出版年份奠涌、出版社、評分磷杏,其中出版年份溜畅,出版社以及價(jià)格是在一行中,這個(gè)我們需要進(jìn)一步處理极祸。
分頁的處理:總記錄是250條慈格,每頁是25條圖書信息,共分了10頁
實(shí)現(xiàn)目標(biāo)一
需要用到的概念:
Item
Item Pipeline
首先建立Scrapy的Item遥金, Scrapy的Item就是我們需要存儲的數(shù)據(jù)結(jié)構(gòu)浴捆,先修改items, 然后在spiders目錄中新建一個(gè)名為bookspider.py的Python文件,由于我們需要在一堆字符串中提取出出版社和價(jià)格等信息所以我們這里需要對抓取的內(nèi)容進(jìn)一步處理汰规, 在這之前還需要修改settings.py文件:
- 加入faker的模擬USER_AGENT數(shù)據(jù)防止被豆瓣屏蔽汤功,
- 也可以設(shè)置DEFAULT_REQUEST_HEADERS參數(shù)。
- 修改ITEM_PIPELINES
代碼如下所示:
items.py
# -*- coding: utf-8 -*-
'''by sudo rm -rf http://imchenkun.com'''
import scrapy
class DoubanBookItem(scrapy.Item):
name = scrapy.Field() # 書名
price = scrapy.Field() # 價(jià)格
edition_year = scrapy.Field() # 出版年份
publisher = scrapy.Field() # 出版社
ratings = scrapy.Field() # 評分
bookspider.py
# -*- coding:utf-8 -*-
'''by sudo rm -rf http://imchenkun.com'''
import scrapy
from douban.items import DoubanBookItem
class BookSpider(scrapy.Spider):
name = 'douban-book'
allowed_domains = ['douban.com']
start_urls = [
'https://book.douban.com/top250'
]
def parse(self, response):
# 請求第一頁
yield scrapy.Request(response.url, callback=self.parse_next)
# 請求其它頁
for page in response.xpath('//div[@class="paginator"]/a'):
link = page.xpath('@href').extract()[0]
yield scrapy.Request(link, callback=self.parse_next)
def parse_next(self, response):
for item in response.xpath('//tr[@class="item"]'):
book = DoubanBookItem()
book['name'] = item.xpath('td[2]/div[1]/a/@title').extract()[0]
book['price'] = item.xpath('td[2]/p/text()').extract()[0]
book['ratings'] = item.xpath('td[2]/div[2]/span[2]/text()').extract()[0]
yield book
pipelines.py
# -*- coding: utf-8 -*-
'''by sudo rm -rf http://imchenkun.com'''
class DoubanBookPipeline(object):
def process_item(self, item, spider):
info = item['price'].split(' / ') # [法] 圣傲锵克蘇佩里 / 馬振聘 / 人民文學(xué)出版社 / 2003-8 / 22.00元
item['name'] = item['name']
item['price'] = info[-1]
item['edition_year'] = info[-2]
item['publisher'] = info[-3]
return item
最后我們到douban的根目錄中執(zhí)行以下命令來運(yùn)行爬蟲來執(zhí)行并導(dǎo)出數(shù)據(jù)到csv文件
scrapy crawl douban-book -o douban_book_top250.csv
csv文件截圖如下:
分析目標(biāo)二
目標(biāo)二是建立在理解了目標(biāo)一的基礎(chǔ)上進(jìn)行的,因?yàn)槎拱甑卿洿螖?shù)過多會(huì)有驗(yàn)證碼出現(xiàn)色解,這里提供一種手工填寫驗(yàn)證碼的方式茂嗓,暫時(shí)不討論如何去識別驗(yàn)證碼,目標(biāo)二的核心概念是如何提交POST表單和登錄成功后帶Cookie的請求科阎。首先我們可以看到頁面結(jié)構(gòu)如下圖所示:
實(shí)現(xiàn)目標(biāo)二
定義Item
# -*- coding: utf-8 -*-import scrapy
'''by sudo rm -rf http://imchenkun.com'''
class DoubanMailItem(scrapy.Item):
sender_time = scrapy.Field() # 發(fā)送時(shí)間
sender_from = scrapy.Field() # 發(fā)送人
url = scrapy.Field() # 豆郵詳細(xì)地址
title = scrapy.Field() # 豆郵標(biāo)題
定義doumailspider
# -*- coding:utf-8 -*-
'''by sudo rm -rf http://imchenkun.com'''
import scrapy
from faker import Factory
from douban.items import DoubanMailItem
import urlparse
f = Factory.create()
class MailSpider(scrapy.Spider):
name = 'douban-mail'
allowed_domains = ['accounts.douban.com', 'douban.com']
start_urls = [
'https://www.douban.com/'
]
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Connection': 'keep-alive',
'Host': 'accounts.douban.com',
'User-Agent': f.user_agent()
}
formdata = {
'form_email': '您的賬號',
'form_password': '您的密碼',
# 'captcha-solution': '',
# 'captcha-id': '',
'login': '登錄',
'redir': 'https://www.douban.com/',
'source': 'None'
}
def start_requests(self):
return [scrapy.Request(url='https://www.douban.com/accounts/login',
headers=self.headers,
meta={'cookiejar': 1},
callback=self.parse_login)]
def parse_login(self, response):
# 如果有驗(yàn)證碼要人為處理
if 'captcha_image' in response.body:
print 'Copy the link:'
link = response.xpath('//img[@class="captcha_image"]/@src').extract()[0]
print link
captcha_solution = raw_input('captcha-solution:')
captcha_id = urlparse.parse_qs(urlparse.urlparse(link).query, True)['id']
self.formdata['captcha-solution'] = captcha_solution
self.formdata['captcha-id'] = captcha_id
return [scrapy.FormRequest.from_response(response,
formdata=self.formdata,
headers=self.headers,
meta={'cookiejar': response.meta['cookiejar']},
callback=self.after_login
)]
def after_login(self, response):
print response.status
self.headers['Host'] = "www.douban.com"
return scrapy.Request(url='https://www.douban.com/doumail/',
meta={'cookiejar': response.meta['cookiejar']},
headers=self.headers,
callback=self.parse_mail)
def parse_mail(self, response):
print response.status
for item in response.xpath('//div[@class="doumail-list"]/ul/li'):
mail = DoubanMailItem()
mail['sender_time'] = item.xpath('div[2]/div/span[1]/text()').extract()[0]
mail['sender_from'] = item.xpath('div[2]/div/span[2]/text()').extract()[0]
mail['url'] = item.xpath('div[2]/p/a/@href').extract()[0]
mail['title'] = item.xpath('div[2]/p/a/text()').extract()[0]
print mail
yield mail
這里需要注意的有三個(gè)地方:
- 第一個(gè)是meta中的cookiejar
Scrapy通過使用 cookiejar
Request meta key來支持單spider追蹤多cookie session述吸。默認(rèn)情況下其使用一個(gè)cookie jar(session),不過您可以傳遞一個(gè)標(biāo)示符來使用多個(gè)锣笨。
- start_requests 我們這里重寫了爬蟲爬取得第一個(gè)頁面蝌矛,這里一開始就進(jìn)去到登錄頁面
- 當(dāng)執(zhí)行爬蟲的時(shí)候,我們需要把打印出來的驗(yàn)證碼地址粘貼到瀏覽器中错英,手動(dòng)輸入到控制上完成驗(yàn)證入撒。
同目標(biāo)一一樣需要設(shè)置settings中的相關(guān)參數(shù),唯一不同的是ITEM_PIPELINES椭岩。
最后我們使用以下命令來啟動(dòng)爬蟲
scrapy crawl douban-mail -o douban_mail_page1.csv
csv文件截圖如下:
Github地址:https://github.com/imchenkun/ick-spider/tree/master/douban
總結(jié)
本篇我們學(xué)習(xí)了如果定義Item以及如何對Item進(jìn)行進(jìn)一步處理(Item Pipeline)茅逮, 還通過登錄豆瓣的案例來了解了如果使用Scrapy進(jìn)行表單提交和Cookie追蹤璃赡,也了解了對于有驗(yàn)證碼的情況該如何處理,當(dāng)然我們這里暫時(shí)還不討論如何識別驗(yàn)證碼献雅。關(guān)于Scrapy的更高級的一些用法和特性可以進(jìn)一步閱讀Scrapy官網(wǎng)的文檔碉考。
特別申明:本文所提到的豆瓣網(wǎng)只是拿來進(jìn)行爬蟲的技術(shù)交流學(xué)習(xí),讀者涉及到的所有侵權(quán)問題都與本人無關(guān)挺身,也希望大家在學(xué)習(xí)實(shí)戰(zhàn)的過程中不要大量的爬取內(nèi)容對服務(wù)器造成負(fù)擔(dān)
本文首發(fā)在sudo rm -rf 采用署名(BY)-非商業(yè)性使用(NC)-禁止演繹(ND) 轉(zhuǎn)載請注明原作者
--EOF--