本文分為兩部分,去哪兒網圖片爬蟲和Scrapy使用詳解。Scrapy使用詳解基于去哪兒網圖片爬蟲進行解析說明。
去哪兒網圖片爬蟲
- 目錄結構
$ scrapy startproject TourLib
Scrapy組件說明
- Scrapy Engine(Scrapy引擎)
Scrapy引擎是用來控制整個系統(tǒng)的數據處理流程,并進行事務處理的觸發(fā)。更多的詳細內容可以看下面的數據處理流程。 - Scheduler(調度)
調度程序從Scrapy引擎接受請求并排序列入隊列,并在Scrapy引擎發(fā)出請求后返還給他們。 - Downloader(下載器)
下載器的主要職責是抓取網頁并將網頁內容返還給蜘蛛( Spiders)。 - Spiders(蜘蛛)
蜘蛛是有Scrapy用戶自己定義用來解析網頁并抓取制定URL返回的內容的類,是用來定義特定網站的抓取和解析規(guī)則。
蜘蛛的整個抓取流程(周期)是這樣的:
- 首先獲取第一個URL的初始請求,當請求返回后調取一個回調函數(parse(self, response))。第一個請求是通過調用start_requests()方法。該方法默認從start_urls中的Url中生成請求,并執(zhí)行解析來調用回調函數。
- 在回調函數(parse)中,你可以解析網頁響應并返回項目對象和請求對象或兩者的迭代。這些請求也將包含一個回調(scrapy.Request(links, callback=self.parse_item)),然后被Scrapy下載,然后有指定的回調parse_item
(self, response)處理。 - 在回調函數parse_item中,你解析網站的內容,使用的是Xpath選擇器(但是你也可以使用BeautifuSoup, lxml或其他任何你喜歡的程序),并生成解析的數據項。
- 最后,從蜘蛛返回的項目通常會進駐到Item Pipeline(項目管道)。
- Item Pipeline(項目管道)
項目管道的主要責任是負責處理有蜘蛛從網頁中抽取的項目,他的主要任務是清洗、驗證和存儲數據。當頁面被蜘蛛解析后,將被發(fā)送到項目管道,并經過幾個特定的次序處理數據。每個項目管道的組件都是有一個簡單的方法組成的Python類。他們獲取了項目并執(zhí)行他們的方法,同時他們還需要確定的是是否需要在項目管道中繼續(xù)執(zhí)行下一步或是直接丟棄掉不處理。
項目管道通常執(zhí)行的過程有:
- 清洗HTML數據
- 驗證解析到的數據(檢查項目是否包含必要的字段)
- 檢查是否是重復數據(如果重復就刪除)
- 將解析到的數據存儲到數據庫,將解析到的圖片存儲到硬盤
piplines就干了兩件事,每次spider處理好一個頁面,將圖片信息傳給它,1.圖片存到硬盤,2.信息存到數據庫
- Downloader middlewares(下載器中間件)
下載中間件是位于Scrapy引擎和下載器之間的鉤子框架,主要是處理 Scrapy引擎與下載器之間的請求及響應。它提供了一個自定義的代碼的方式來拓展Scrapy的功能。下載中間器是一個處理請求和響應的鉤子框架。他是 輕量級的,對Scrapy盡享全局控制的底層的系統(tǒng)。 - Spider middlewares(蜘蛛中間件)
蜘蛛中間件是介于Scrapy引擎和蜘蛛之間的鉤子框架,主要工作是處理蜘蛛 的響應輸入和請求輸出。它提供一個自定義代碼的方式來拓展Scrapy的功能。蛛中間件是一個掛接到Scrapy的蜘蛛處理機制的框架,你可以插入自定義 的代碼來處理發(fā)送給蜘蛛的請求和返回蜘蛛獲取的響應內容和項目。 - Scheduler middlewares(調度中間件)
調度中間件是介于Scrapy引擎和調度之間的中間件,主要工作是處從Scrapy引擎發(fā)送到調度的請求和響應。他提供了一個自定義的代碼來拓展Scrapy的功能。前陣子想爬點二手車數據賺錢,專門搗鼓了一兩個星期的scrapy,雖然最后因為各種原因,賺錢并不如意,但也學到了爬蟲的一些基本技術,現在記錄下來,以備后續(xù)使用。
添加mysql支持
- settings.py中添加如下配置項
# start MySQL database configure setting
MYSQL_HOST = 'localhost'
MYSQL_DBNAME = 'cnblogsdb'
MYSQL_USER = 'root'
MYSQL_PASSWD = 'root'
# end of MySQL database configure setting
- 在piplines.py中添加數據庫操作如下:
class ImageDownloadPipeline(object):
def process_item(self, item, spider):
db = MySQLdb.connect("localhost","root","mypassword","test_db" )
cursor = db.cursor()
if 'image_urls' in item:
images = []
dir_path = '%s/%s/%s' % (settings.IMAGES_STORE,item['place'],item['name'])
##item['url'] = <200 www.explame.com>
urls = str(item['url'])[5:-1]
if not os.path.exists(dir_path):
os.makedirs(dir_path)
for image_url in item['image_urls']:
image_file_name = image_url[-15:]
file_path = '%s/%s' % (dir_path, image_file_name)
images.append(file_path)
if os.path.exists(file_path):
continue
with open(file_path, 'wb') as handle:
response = requests.get(image_url, stream=True)
for block in response.iter_content(1024):
if not block:
break
handle.write(block)
sql = "INSERT INTO tour_tbl (tour_title,tour_icourl,local_url) VALUES ( '%s','%s','%s' )" % ( image_file_name,image_url,urls)
try:
# 執(zhí)行sql語句
cursor.execute(sql)
# 提交到數據庫執(zhí)行
db.commit()
except:
# 發(fā)生錯誤時回滾
db.rollback()
item['images'] = images
# 關閉數據庫連接
db.close()
return item
- 在settins.py中添加ImageDownloadPipeline
ITEM_PIPELINES = {'qunar.pipelines.ImageDownloadPipeline': 1}
Xpath使用
示例
xpath類似beautifulsoup解析html結構,省去了正則表達式的麻煩
<html>
<head></head>
<body>
<div>
<p><a > more information </a></p>
</div>
</body>
</html>
- xpath('//div//a')
[<a > more information </a>] - xpath('//div/*')
div中所有元素 - xpath('//div/a/@href')
[http://www.iana.org] - xpath('//div/a/text()').extract()
'more information'
xpath參考教程
這是個視頻教程,是我學習xpath的最好的教程,看完真的是一下就明白了。
XPath 與多線程爬蟲
Scrapy定向爬蟲教程(二)——提取網頁內容
多頁面爬取
多頁面爬取有兩種形式
1)從某一個或者多個主頁中獲取多個子頁面的url列表,parse()函數依次爬取列表中的各個子頁面。
#先獲取url list,然后根據list爬取各個子頁面內容
fromtutorial.items import DmozItem
classDmozSpider(scrapy.Spider):
name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls =["http://www.dmoz.org/Computers/Programming/Languages/Python/",]
def parse(self, response):
for href inresponse.css("ul.directory.dir-col > li > a::attr('href')"):
#獲取當前頁面的url:respone.url
#通過拼接response.url和href.extract(),將相對網址轉換為絕對網址
url =response.urljoin(response.url, href.extract())
yield scrapy.Request(url, callback=self.parse_dir_contents)
#負責子頁面內容的爬取
def parse_dir_contents(self, response):
for sel in response.xpath('//ul/li'):
item = DmozItem()
item['title'] =sel.xpath('a/text()').extract()
item['link'] = sel.xpath('a/@href').extract()
item['desc'] =sel.xpath('text()').extract()
yield item
2)從遞歸爬取,這個相對簡單。在scrapy中只要定義好初始頁面以及爬蟲規(guī)則rules,就能夠實現自動化的遞歸爬取。
yield和return的區(qū)別
- yield
yield是用于生成器。什么是生成器,你可以通俗的認為,在一個函數中,使用了yield來代替return的位置的函數,就是生成器。它不同于函數的使用方法是:函數使用return來進行返回值,每調用一次,返回一個新加工好的數據返回給你;yield不同,它會在調用生成器的時候,把數據生成object,然后當你需要用的時候,要用next()方法來取,同時不可逆。你可以通俗的叫它"輪轉容器",可用現實的一種實物來理解:水車,先yield來裝入數據、產出generator object、使用next()來釋放;好比水車轉動后,車輪上的水槽裝入水,隨著輪子轉動,被轉到下面的水槽就能將水送入水道中流入田里。
def func3():
for i in range(1,5):
yield i#裝入
gob = func3()#generator 類型
print next(gob)#1 釋放的第一個裝入的數據,(先入先出)
print next(gob)#2
print next(gob)#3
print next(gob)#4
print next(gob)#報錯
個人理解,yield在python內部是當作list處理的:
def func3():
for i in range(1,5):
yield i
yi = []
yi = func3()
for y in yi:
print y
輸出:
1
2
3
4
- return
這個大家都知道,return既可以終止函數的執(zhí)行,也可以返回函數加工處理好的數據。