scrapy 爬取 去哪網(wǎng) 游記內(nèi)容 圖片

書接上文,前面用pyspider實(shí)現(xiàn)了去哪網(wǎng)的游記爬取數(shù)據(jù)存儲(chǔ)
然后學(xué)習(xí)了scrapy之后,用scrapy再次實(shí)現(xiàn)了一次,通過(guò)實(shí)際操做,加深對(duì)scrapy的理解

環(huán)境介紹:
MacOS Mojave 10.14.5+VSCode1.37.1+Python3.7

1 創(chuàng)建項(xiàng)目

scrapy start project quna

然后項(xiàng)目就創(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

查看工程目錄下的文件


image.png

而我們處理的就是spiders目錄下的quna.py

image.png

上面是剛創(chuàng)建的
下面放出爬取去哪網(wǎng)的完整代碼,相關(guān)的點(diǎn),我都在代碼里做了注釋
quna.py

# -*- coding: utf-8 -*-
import os
import scrapy
from scrapy import Selector
from qunaScrapy.items import ImageItem #后面會(huì)有講解

#設(shè)置爬取結(jié)果存放的路徑
DIR_PATH = '/Users/lzx-mac-baibing/Desktop/去哪網(wǎng)游記Scrapy'
#設(shè)置分頁(yè)請(qǐng)求的數(shù)量上限
MAX_PAGE = 50


class QunaSpider(scrapy.Spider):
    #項(xiàng)目的唯一名,用來(lái)區(qū)分不同的Spider   
    name = 'quna' 
    #允許爬取的域名,凡事不在這里的域名下的請(qǐng)求,都會(huì)被過(guò)濾  
    allowed_domains = ['travel.qunar.com','tr-osdcp.qunarzz.com']
    #spider啟動(dòng)時(shí),初始化請(qǐng)求的地址
    start_urls = ['http://travel.qunar.com/travelbook/list.htm/']
    #分頁(yè)請(qǐng)求時(shí)使用    
    page=1

    def __init__(self):
        #初始化文件操作類
        self.deal = Deal()
    
    #初始化請(qǐng)求默認(rèn)回掉的方法,作為我們所有解析的入口
    #作為scrapy的學(xué)習(xí)項(xiàng)目,這里我只是實(shí)現(xiàn)了爬取第一頁(yè)數(shù)據(jù)并獲取對(duì)應(yīng)詳情的邏輯
    #如果有需要,也可以在parse中實(shí)現(xiàn)再套一層邏輯,處理page切換
    def parse(self, response):
        #這里獲取的li標(biāo)簽下,class=tit a標(biāo)簽的href數(shù)據(jù),也就是所有標(biāo)題關(guān)聯(lián)的相對(duì)url地址
        #對(duì)應(yīng)的網(wǎng)頁(yè)數(shù)據(jù)如下圖圖片A所示結(jié)構(gòu)
        for each in response.css('li > .tit > a').xpath('@href').extract():
            #用獲取的相對(duì)路徑生成完整的路徑
            url = response.urljoin(each)
            #回掉詳情
            yield scrapy.Request(url=url,callback=self.detail_page,dont_filter=True)

    ##對(duì)應(yīng)帶分頁(yè)數(shù)據(jù)請(qǐng)求的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  標(biāo)簽下的data-original屬性
        images = response.css('.js_lazyimg').xpath('@data-original').extract()
        #獲取title id=booktitle 的文本信息
        title = response.css('#booktitle::text').extract_first()
        #給每個(gè)游記用title創(chuàng)建個(gè)文件夾
        dir_path = self.deal.mkDir(title)
        #圖片多了有些亂,加個(gè)目錄存放圖片
        self.deal.mkDir(title+'/圖片')
        #獲取標(biāo)簽以及子標(biāo)簽的文本,遍歷所有的元素,獲得標(biāo)簽文本
        contents = response.xpath('//div[@class="b_panel_schedule"]//text()').extract()
        #將獲取的搜有內(nèi)容文本,給他拼起來(lái)
        content = ''
        for text in contents:
            content = content + '\n' + text
        if dir_path:
            #將文本信息以txt存儲(chǔ)到指定目錄下,也就是我們前面創(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

圖片A

3 創(chuàng)建item

item 是保存爬取數(shù)據(jù)的容器,和字典類似,比字典多了額外保護(hù),可以避免拼寫錯(cuò)誤或者定義字段錯(cuò)誤,反正就是直接報(bào)錯(cuò)……別問(wèn)我咋知道的??

我們后續(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)入即可

上述的完工了,就能啟動(dòng)爬蟲了,只是圖片沒(méi)法下載和存儲(chǔ)

scrapy crawl quna

接下來(lái),我們需要處理圖片

4 設(shè)置Item Pipeline

項(xiàng)目管道,當(dāng)item生成后,會(huì)自動(dòng)被送到這來(lái)處理。

代碼實(shí)現(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

#這個(gè)生成項(xiàng)目的時(shí)候就有了,必須實(shí)現(xiàn)process_item
class QunascrapyPipeline(object):
    def process_item(self, item, spider):
        return item
    
#自定義實(shí)現(xiàn)文件下載處理

#def item_completed(self,results,sipders...):
class QunaImgDownloadPipeline(ImagesPipeline):
    #獲取圖片地址,發(fā)起請(qǐng)求
    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):
        #獲取圖片的保存的相對(duì)路徑,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]
        #將下載好的文件,移到對(duì)應(yīng)的游記目錄下
        shutil.move(readl_path,item['dir_path'])
        return item

4 配置setting 激活管道

修改部分的代碼如下

#鍵-需要打開的ItemPipeline類
#值-優(yōu)先級(jí),數(shù)字0-1000,數(shù)字越小,優(yōu)先級(jí)越高
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)游記代碼部分完成
將所有修改的文件保存,再次啟動(dòng)爬蟲
結(jié)果如下


image.png

后記:過(guò)程中遇到的問(wèn)題

1 response.css 和 response.xpath的使用不熟悉,可以加強(qiáng)
2 allowed_domains 中要將自己所有后續(xù)用到的添加進(jìn)去,要不然被過(guò)濾了就很尷尬,第一次處理圖片時(shí),發(fā)現(xiàn)圖片請(qǐng)求沒(méi)反應(yīng),然后發(fā)現(xiàn)地址和主站地址域名不一樣
3
后續(xù)再根據(jù)學(xué)習(xí)內(nèi)容,對(duì)這個(gè)再優(yōu)化升級(jí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容