*本文在Windows+pycharm(Python3.5)+scrapy環境下完成爬蟲工作。
一. scrapy原理及本文爬取思路簡介:
1.scrapy經典原理圖講解:
- Scrapy是一個用 Python 寫的 Crawler Framework,是基於Twisted的異步處理框架,是純python實現的快速,高層次的屏幕抓取和web抓取框架,用戶只需要定製開發幾個模塊就可以輕鬆的實現一個爬蟲,用來抓取網頁內容或者各種圖片。Scrapy提供了一個item pipeline ,來下載屬於某個特定項目的圖片 。這條管道被稱作圖片管道,在ImagesPipeline
類中實現,可避免重新下載最近已經下載過的圖片。下圖顯示了Scrapy的大體架構:
注意到圖片中心是引擎控制着整個爬取工作的運行。Scrapy運行流程如下:
- 引擎打開一個網站(open a domain),找到處理該網站的Spider並向該 spider請求第一個要爬取的URL(s)。
-引擎從Spider中獲取到第一個要爬取的URL並在調度器(Scheduler)以Request調度。 - 引擎向調度器請求下一個要爬取的URL。
- 調度器返回下一個要爬取的URL給引擎,引擎將URL通過下載中間件(請求(request)方向)轉發給下載器(Downloader)。
- 一旦頁面下載完畢,下載器生成一個該頁面的Response,並將其通過下載中間件(返回(response)方向)發送給引擎。
- 引擎從下載器中接收到Response並通過Spider中間件(輸入方向)發送給Spider處理。
- Spider處理Response並返回爬取到的Item及(跟進的)新的Request給引擎。
- 引擎將(Spider返回的)爬取到的Item給Item Pipeline,將(Spider返回的)Request給調度器。
- (從第二步)重複直到調度器中沒有更多的request,引擎關閉該網站。
2.本文爬取思路簡介:
- 進入到onlylady網站圖片網http://pic.onlylady.com/cate-10004_50_3.shtml
- 首先設定start_url(這裏很方便直接設置了四個,50是最後一頁,相當於程序設置倒着爬,這樣便於四類統一)
- 我們爬完一頁時候需要找到類別title,圖片url(找到的是小圖,程序中要設置調整圖片大小),然後還要找到下一次要爬取的頁的url鏈接。我這裏是用火狐瀏覽器的原審查元素功能+firebug審查元素功能查看xpath表達式的。接着進入爬蟲。
二.爬取流程及代碼
1.爬取流程
-創建爬蟲工程:cmd命令下進入你的某目錄:
scrapy startproject jiandan
-創建爬蟲文件jd
cd jiandan
scrapy genspider -t basic jd onlylady.com
看下生成的項目結構:
-開始編寫程序啦:
設定初始start_url
編寫spiders:主要完成新的url列表解析和圖片鏈接解析。
編寫圖片管道:實現圖片自動下載,縮略圖下載,遇到錯誤非圖片鏈接會自動拋棄,不重複下載的任務。(設置存儲目錄)
Setting:設置打開圖片管道,設置存儲位置,縮略圖尺寸,ROBOTSTXT_OBEY = False等。
(下面附程序及下載結果,下載速度挺快的)
2.代碼
- items.py文件
import scrapy
class JiandanItem(scrapy.Item):
title = scrapy.Field()#類別,用來生成存儲目錄
image_urls = scrapy.Field() # 圖片的鏈接
images = scrapy.Field()#自動生成的存儲圖片url,圖片hash和checksum
- spiders的jd.py文件
# -*- coding: utf-8 -*-
import scrapy
from jiandan.items import JiandanItem
from scrapy.selector import Selector
from scrapy.linkextractors import LinkExtractor
from scrapy.http import HtmlResponse,Request
import logging#寫不寫都行,用來把log寫入文件file_name
class jiandanSpider(scrapy.Spider):
name = 'onlylady'#名字可調
allowed_domains = ['onlylady.com']
start_urls = ["http://pic.onlylady.com/cate-10004_50_3.shtml","http://pic.onlylady.com/cate-10009_50_3.shtml","http://pic.onlylady.com/cate-10011_50_3.shtml","http://pic.onlylady.com/cate-10060_50_3.shtml"]#初始的url,scrapy很方便強大吧
def parse(self, response):
imageurl=[]
item = JiandanItem()
item['title']=''.join(response.xpath('//head/title/text()').extract()[0])#根據xpath獲取title,此處 ''.join()是爲了在後面爲圖片自定義名稱時使用,若不加''.join(),後面調用item['title']會得到Unicode碼
imageurl = response.xpath('//img/@src').extract() # 提取圖片鏈接
item['image_urls']=[i.replace('375x375','985x695') for i in imageurl]#小圖轉大圖鏈接
# print 'image_urls',item['image_urls']
yield item
n_url = response.xpath('//a[@class="n"]//@href').extract_first() # 翻頁
new_url = "http://pic.onlylady.com/" + str(n_url)#構造出下頁的url
# print 'new_url',new_url
if new_url:
yield scrapy.Request(new_url, callback=self.parse)#根據scrapy爬蟲流程,回調函數用來把new_url傳到調度器生成request
# self.log("your log information")
- pipelines.py
import os
import urllib
import scrapy
import json
import codecs
from scrapy.exceptions import DropItem
from scrapy.contrib.pipeline.images import ImagesPipeline
from scrapy.pipelines.images import ImagesPipeline
from jiandan import settings
class JiandanPipeline(object):#用來自定義圖片存儲
def __init__(self):
self.file = codecs.open('jiandan.json', 'w', encoding='utf-8')#title是中文,需轉碼#當運行scrapy crawl onlylady -o items.json後,數據默認保存爲items.json,裏面中文全爲Unicode,重新打開或創建一個文件'jiandan.json',名稱隨意
def process_item(self, item, spider):
line = json.dumps(dict(item), ensure_ascii=False) + "\n"
self.file.write(line)
return item
def spider_closed(self, spider):
self.file.close()
class JiandanPipeline(ImagesPipeline): # 繼承ImagesPipeline這個類,實現這個功能
def get_media_requests(self, item, info): # 重寫ImagesPipeline get_media_requests方法
for image_url in item['image_urls']:
yield scrapy.Request(image_url,meta={'item':item})
def item_completed(self, results, item, info):
image_paths = [x['path'] for ok, x in results if ok]
if not image_paths:
raise DropItem("Item contains no images")
#item['image_paths'] = image_paths
return item
def file_path(self, request, response=None, info=None):#自定義存儲路徑
item = request.meta['item'] # 通過上面的meta傳遞過來item
image_guid = request.url.split('/')[-1]
filename = u'full/{0}/{1}'.format(item['title'], image_guid)#title爲二級目錄
return filename
- settings.py
BOT_NAME = 'jiandan'
SPIDER_MODULES = ['jiandan.spiders']
NEWSPIDER_MODULE = 'jiandan.spiders'
ROBOTSTXT_OBEY = False
LOG_FILE ="file_name"#日誌文件
ITEM_PIPELINES = {'jiandan.pipelines.JiandanPipeline': 300,
'jiandan.pipelines.ImagesPipeline':1,
}#開啓兩個管道
#ITEM_PIPELINES = {'scrapy.contrib.pipeline.images.ImagesPipeline': 1}
IMAGES_STORE='f:\\onlylady'#設置自己的存儲路徑
#我在這裏關閉縮略圖功能了
'''IMAGES_THUMBS = {#縮略圖的尺寸,設置這個值就會產生縮略圖
'small': (50, 50),
'big': (200, 200),
}'''
-大功告成,cmd命令下 scrapy crawl onlylady
-爬取結果部分: