書接上文它浅,前面用pyspider實現(xiàn)了去哪網(wǎng)的游記爬取數(shù)據(jù)存儲
然后學(xué)習(xí)了scrapy之后羊娃,用scrapy再次實現(xiàn)了一次翼馆,通過實際操做东且,加深對scrapy的理解
環(huán)境介紹:
MacOS Mojave 10.14.5+VSCode1.37.1+Python3.7
1 創(chuàng)建項目
scrapy start project quna
然后項目就創(chuàng)建好了
(base) bogon:~ blaze$ scrapy startproject qunaScrapy
New Scrapy project 'qunaScrapy', using template directory '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/scrapy/templates/project', created in:
/Users/blaze/qunaScrapy
You can start your first spider with:
cd qunaScrapy
scrapy genspider example example.com
(base) bogon:~ blaze$ cd qunaScrapy/
(base) bogon:qunaScrapy blaze $ ls
qunaScrapy scrapy.cfg
(base) bogon:qunaScrapy blaze$
2 創(chuàng)建Spider
scrapy genspider quna travel.qunar.com
查看工程目錄下的文件
而我們處理的就是spiders目錄下的quna.py
上面是剛創(chuàng)建的
下面放出爬取去哪網(wǎng)的完整代碼,相關(guān)的點启具,我都在代碼里做了注釋
quna.py
# -*- coding: utf-8 -*-
import os
import scrapy
from scrapy import Selector
from qunaScrapy.items import ImageItem #后面會有講解
#設(shè)置爬取結(jié)果存放的路徑
DIR_PATH = '/Users/lzx-mac-baibing/Desktop/去哪網(wǎng)游記Scrapy'
#設(shè)置分頁請求的數(shù)量上限
MAX_PAGE = 50
class QunaSpider(scrapy.Spider):
#項目的唯一名,用來區(qū)分不同的Spider
name = 'quna'
#允許爬取的域名珊泳,凡事不在這里的域名下的請求鲁冯,都會被過濾
allowed_domains = ['travel.qunar.com','tr-osdcp.qunarzz.com']
#spider啟動時拷沸,初始化請求的地址
start_urls = ['http://travel.qunar.com/travelbook/list.htm/']
#分頁請求時使用
page=1
def __init__(self):
#初始化文件操作類
self.deal = Deal()
#初始化請求默認回掉的方法,作為我們所有解析的入口
#作為scrapy的學(xué)習(xí)項目薯演,這里我只是實現(xiàn)了爬取第一頁數(shù)據(jù)并獲取對應(yīng)詳情的邏輯
#如果有需要撞芍,也可以在parse中實現(xiàn)再套一層邏輯,處理page切換
def parse(self, response):
#這里獲取的li標簽下跨扮,class=tit a標簽的href數(shù)據(jù)序无,也就是所有標題關(guān)聯(lián)的相對url地址
#對應(yīng)的網(wǎng)頁數(shù)據(jù)如下圖圖片A所示結(jié)構(gòu)
for each in response.css('li > .tit > a').xpath('@href').extract():
#用獲取的相對路徑生成完整的路徑
url = response.urljoin(each)
#回掉詳情
yield scrapy.Request(url=url,callback=self.detail_page,dont_filter=True)
##對應(yīng)帶分頁數(shù)據(jù)請求的parse方法
# def parse(self, response):
# print('====================== ',self.page)
# for each in response.css('li > .tit > a').xpath('@href').extract():
# url = response.urljoin(each)
# yield scrapy.Request(url=url,callback=self.detail_page,dont_filter=True)
# if self.page < MAX_PAGE:
# self.page += 1
# next = response.css('.next').xpath('@href').extract_first()
# if next:
# nextUrl = next
# if next.startswith('http')==False:
# if next.startswith('//'):
# nextUrl = 'http:'+ next
# yield scrapy.Request(url=nextUrl,callback=self.parse,dont_filter=True)
#詳情解析
def detail_page(self,response):
#獲取圖片地地址 class=js_lazyimg 標簽下的data-original屬性
images = response.css('.js_lazyimg').xpath('@data-original').extract()
#獲取title id=booktitle 的文本信息
title = response.css('#booktitle::text').extract_first()
#給每個游記用title創(chuàng)建個文件夾
dir_path = self.deal.mkDir(title)
#圖片多了有些亂,加個目錄存放圖片
self.deal.mkDir(title+'/圖片')
#獲取標簽以及子標簽的文本衡创,遍歷所有的元素帝嗡,獲得標簽文本
contents = response.xpath('//div[@class="b_panel_schedule"]//text()').extract()
#將獲取的搜有內(nèi)容文本,給他拼起來
content = ''
for text in contents:
content = content + '\n' + text
if dir_path:
#將文本信息以txt存儲到指定目錄下璃氢,也就是我們前面創(chuàng)建的文件夾下
self.deal.saveContent(content,dir_path,title)
#圖片的處理哟玷,后續(xù)詳解
for img in images:
if img:
file_name = self.deal.getFileName(img)
file_path = dir_path+'/圖片/'+file_name
item = ImageItem()
item['src'] = [img]
item['dir_path']=file_path
yield item
#下面這些就不講了
class Deal:
def __init__(self):
self.path = DIR_PATH
if not self.path.endswith('/'):
self.path = self.path + '/'
if not os.path.exists(self.path):
os.makedirs(self.path)
def mkDir(self, path):
path = path.strip()
dir_path = self.path + path
exists = os.path.exists(dir_path)
if not exists:
os.makedirs(dir_path)
return dir_path
else:
return dir_path
def saveContent(self, content, dir_path, name):
file_name = dir_path + "/" + name + ".txt"
f = open(file_name, "w+")
f.write(content)
def getFileName(self, url):
(url, tempfilename) = os.path.split(url)
return tempfilename
3 創(chuàng)建item
item 是保存爬取數(shù)據(jù)的容器,和字典類似拔莱,比字典多了額外保護碗降,可以避免拼寫錯誤或者定義字段錯誤,反正就是直接報錯……別問我咋知道的??
我們后續(xù)需要使用的就是下載地址和保存路徑
完整代碼如下
item.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class ImageItem(scrapy.Item):
src=scrapy.Field()
dir_path=scrapy.Field()
然后spider中用from qunaScrapy.items import ImageItem導(dǎo)入即可
上述的完工了塘秦,就能啟動爬蟲了讼渊,只是圖片沒法下載和存儲
scrapy crawl quna
接下來,我們需要處理圖片
4 設(shè)置Item Pipeline
項目管道尊剔,當item生成后爪幻,會自動被送到這來處理。
代碼實現(xiàn)如下 pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import scrapy
from qunaScrapy.items import ImageItem
import shutil,os,pymysql
from scrapy.pipelines.images import ImagesPipeline
#這個生成項目的時候就有了须误,必須實現(xiàn)process_item
class QunascrapyPipeline(object):
def process_item(self, item, spider):
return item
#自定義實現(xiàn)文件下載處理
#def item_completed(self,results,sipders...):
class QunaImgDownloadPipeline(ImagesPipeline):
#獲取圖片地址,發(fā)起請求
def get_media_requests(self, item, info):
for image_url in item['src']:
yield scrapy.Request(image_url)
#下載結(jié)束后回調(diào)的方法
def item_completed(self, results, item, info):
#獲取圖片的保存的相對路徑挨稿,full/****.jpg
image_paths = [x['path'] for ok, x in results if ok]
#生成完全地址
readl_path = '/Users/lzx-mac-baibing/Desktop/去哪網(wǎng)游記Scrapy/圖集'+'/'+image_paths[0]
#將下載好的文件,移到對應(yīng)的游記目錄下
shutil.move(readl_path,item['dir_path'])
return item
4 配置setting 激活管道
修改部分的代碼如下
#鍵-需要打開的ItemPipeline類
#值-優(yōu)先級京痢,數(shù)字0-1000奶甘,數(shù)字越小,優(yōu)先級越高
ITEM_PIPELINES = {
'qunaScrapy.pipelines.QunascrapyPipeline': 1000,
'qunaScrapy.pipelines.QunaImgDownloadPipeline':1
}
#設(shè)置的full文件存放的路徑
IMAGES_STORE = '/Users/lzx-mac-baibing/Desktop/去哪網(wǎng)游記Scrapy/圖集'
#ImageItem中定義的src
IMAGES_URLS_FIELD = 'src'
至此祭椰,使用srcapy爬取去哪網(wǎng)游記代碼部分完成
將所有修改的文件保存臭家,再次啟動爬蟲
結(jié)果如下
后記:過程中遇到的問題
1 response.css 和 response.xpath的使用不熟悉,可以加強
2 allowed_domains 中要將自己所有后續(xù)用到的添加進去方淤,要不然被過濾了就很尷尬钉赁,第一次處理圖片時,發(fā)現(xiàn)圖片請求沒反應(yīng)携茂,然后發(fā)現(xiàn)地址和主站地址域名不一樣
3
后續(xù)再根據(jù)學(xué)習(xí)內(nèi)容你踩,對這個再優(yōu)化升級