python網(wǎng)絡(luò)爬蟲之Scrapy

本文分享的大體框架包含以下三部分

(1)首先介紹html網(wǎng)頁(yè),用來(lái)解析html網(wǎng)頁(yè)的工具xpath
(2)介紹python中能夠進(jìn)行網(wǎng)絡(luò)爬蟲的庫(kù)(requests,lxml,scrapy等)
(3)從四個(gè)案例出發(fā)有易到難依次介紹scrapy集成爬蟲框架

下面開始對(duì)三部分內(nèi)容逐一開始介紹。

一、html和xpath說(shuō)明

1. html

超文本標(biāo)記語(yǔ)言,是用來(lái)描述網(wǎng)頁(yè)的一種語(yǔ)言。主要用于控制數(shù)據(jù)的顯示和外觀。HTML文檔一定意義上可以被稱為網(wǎng)頁(yè)。但反過(guò)來(lái)說(shuō)網(wǎng)頁(yè)不僅僅是HTML,網(wǎng)頁(yè)本質(zhì)有三部分構(gòu)成:負(fù)責(zé)內(nèi)容結(jié)構(gòu)的HTML,負(fù)責(zé)表現(xiàn)的CSS,以及負(fù)責(zé)行為的javascript。本文主要分享的是最核心的內(nèi)容結(jié)構(gòu)部分。

(1)html結(jié)構(gòu)

完整的HTML文件至少包括<HTML>標(biāo)簽、<HEAD>標(biāo)簽、<TITLE>標(biāo)簽和<BODY>標(biāo)簽,并且這些標(biāo)簽都是成對(duì)出現(xiàn)的,開頭標(biāo)簽為<>,結(jié)束標(biāo)簽為</>,在這兩個(gè)標(biāo)簽之間添加內(nèi)容。通過(guò)這些標(biāo)簽中的相關(guān)屬性可以設(shè)置頁(yè)面的背景色、背景圖像等。
例如,我們打開豆瓣首頁(yè),摁下鍵盤上的F12鍵,打開瀏覽器自帶“開發(fā)者工具”,可以看到一個(gè)完整的html文檔結(jié)構(gòu),如下圖

HTML文檔結(jié)構(gòu).jpg

從上圖可以看出,一個(gè)完整的html文檔主要包含三部分:DTD文檔頭,head頭部信息和body正文信息。其中DTD文檔頭用來(lái)告訴瀏覽器執(zhí)行標(biāo)準(zhǔn)是什么(比如html4或是html5),head頭部信息用來(lái)說(shuō)明瀏覽器的編碼方式和文檔頭名稱,body顧名思義就是瀏覽器的正文部分。

(2)html標(biāo)簽

作為開始和結(jié)束的標(biāo)記,由尖括號(hào)包圍的關(guān)鍵詞,比如 <html>,標(biāo)簽對(duì)中的第一個(gè)標(biāo)簽是開始標(biāo)簽,第二個(gè)標(biāo)簽是結(jié)束標(biāo)簽。html中常見標(biāo)簽如下:

html常用標(biāo)簽.png
html常用標(biāo)簽2.png

其中, “< ul >< li ></li ></ul >”是一種嵌套順序,無(wú)序列表,成對(duì)出現(xiàn);li的父元素必須是ul或者ol,不同之處在于ol是一種有序列列表,而ul是無(wú)序列表;

(3)html屬性

屬性是用來(lái)修飾標(biāo)簽的,放在開始標(biāo)簽里里面,html中常見四大屬性:

屬性 說(shuō)明
class 規(guī)定元素的類名,大多數(shù)時(shí)候用于指定樣式表中的類
id 唯一標(biāo)識(shí)一個(gè)元素的屬性,在html里面必須是唯一的
href 指定超鏈接目標(biāo)的url
src 指定圖像的url

2. xpath

(1)xpath定義

是一種路徑查詢語(yǔ)言,簡(jiǎn)單的說(shuō)就是利用一個(gè)路徑表達(dá)式從html文檔中找到我們需要的數(shù)據(jù)位置,進(jìn)而將其寫入到本地或者數(shù)據(jù)庫(kù)中。(可以將xpath類比為sql結(jié)構(gòu)化查詢語(yǔ)言)

(2)xpath常見使用方法

符號(hào) 功能
// 表示在整個(gè)文本中查找,是一種相對(duì)路徑
/ 表示則表示從根節(jié)點(diǎn)開始查找,是一種絕對(duì)路徑
text() 找出文本值
@ 找出標(biāo)簽對(duì)應(yīng)的屬性值,比如@href就是找出對(duì)應(yīng)的href鏈接
. 表示當(dāng)前節(jié)點(diǎn)
.. 表示當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)

當(dāng)然xpath除了上述常見用法外,還存兩種比較特殊的用法:以相同的字符開頭;標(biāo)簽套標(biāo)簽。

用法1:以相同的字符開頭:starts-with(@屬性部分,屬性字符相同部分

用法2:標(biāo)簽套標(biāo)簽:string(.)

#以相同的字符開頭
#比如我們想同時(shí)提取到下列html中三條文本內(nèi)容的話,就需要使用starts-with方法
html1 = """
<!DOCTYPE html>
<html>
 <head lang='en'>
    <meta charest='utf-8'>
    <title></title>
 </head>
 <body>
    <div id="test-1">需要的內(nèi)容1</div>
    <div id="test-2">需要的內(nèi)容2</div>
    <div id="testfault">需要的內(nèi)容3</div>
 </body>
</html>

#爬取代碼
from lxml import etree
selector = etree.HTML(html1)
content  = selector.xpath('//div[starts-with(@id,"test")]/text()')
for each in content:
    print each

還有一種是標(biāo)簽套標(biāo)簽形式,參考如下例子

html2 = """
<!DOCTYPE html>
<html>
 <head lang='en'>
    <meta charest='utf-8'>
    <title></title>
 </head>
 <body>
    <div id="test3">
    我左青龍,
        <span id='tiger'>
            右白虎
            <ul>上朱雀,
                <li>下玄武,</li>
            </ul>
        </span>
        龍頭在胸口
    </div>
 </body>
</html>
"""
#如果我們想爬取的內(nèi)容是html文檔中的所有文本的話,需要使用string方法進(jìn)行提取
selector2 = etree.HTML(html2)
content2  = selector2.xpath('//div[@id="test3"]')[0] #列表,只有一個(gè)元素
info = content2.xpath('string(.)')
content3 = info.replace('\n','').replace(' ','')
print content3

(3)xpath的謂語(yǔ)結(jié)構(gòu)

該小節(jié)參考資料:阮一峰的網(wǎng)絡(luò)日志

所謂"謂語(yǔ)條件",就是對(duì)路徑表達(dá)式的附加條件。所有的條件,都寫在方括號(hào)"[]"中,表示對(duì)節(jié)點(diǎn)進(jìn)行進(jìn)一步的篩選。例如:

<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
  <book>
    <title lang="eng">Harry Potter</title>
    <price>29.99</price>
  </book>
  <book>
    <title lang="eng">Learning XML</title>
    <price>39.95</price>
  </book>
</bookstore>

下面從幾個(gè)簡(jiǎn)單的例子讓大家體會(huì)一下

  • /bookstore/book[1] :表示選擇bookstore的第一個(gè)book子元素。
  • /bookstore/book[last()] :表示選擇bookstore的最后一個(gè)book子元素。
  • /bookstore/book[last()-1] :表示選擇bookstore的倒數(shù)第二個(gè)book子元素。
  • /bookstore/book[position()<3] :表示選擇bookstore的前兩個(gè)book子元素。
  • //title[@lang] :表示選擇所有具有l(wèi)ang屬性的title節(jié)點(diǎn)。
  • //title[@lang='eng'] :表示選擇所有l(wèi)ang屬性的值等于"eng"的title節(jié)點(diǎn)。

二、python中能夠進(jìn)行網(wǎng)絡(luò)爬蟲的庫(kù)

1. 安裝方式

python中安裝包或者模塊的方式一般有以下兩種:

(1)pip install xxx(xxx表示模塊名字)

pip install lxml/numpy/pandas/scrapy/requests

(2)進(jìn)入到python庫(kù)網(wǎng)站下載所需模塊,然后使用pip install xxx.whl安裝即可

pip install lxml?3.7.3?cp27?cp27m?win_amd64.whl

2. requests

import requests
#我的簡(jiǎn)書主頁(yè)
r = requests.get('http://www.itdecent.cn/u/95f3a80fac3e')
# r本身是一個(gè)reponse對(duì)象,需要通過(guò)content來(lái)返回其內(nèi)容
print r.content
#其實(shí)上面通過(guò)content之后得到就是一個(gè)完整的html文檔,之后可以直接使用lxml等工具直接對(duì)其進(jìn)行解析,下一小節(jié)會(huì)講到lxml
print r.status_code
print r.encoding #html的編碼方式,一般是UTF-8
print r.cookies

3. lxml

lxml中集成了剛才講述的xpath這種路徑查詢語(yǔ)言;例如我們首先創(chuàng)建一個(gè)html文檔如下

html= """
<!DOCTYPE html>
<html>
 <head lang='en'>
    <meta charest='utf-8'>
    <title></title>
 </head>
 <body>
    <div id="test-1">需要的內(nèi)容1</div>
    <div id="test-2">需要的內(nèi)容2</div>
    <div id="testfault">需要的內(nèi)容3</div>
 </body>
</html>
"""

然后使用lxml對(duì)我們想要的內(nèi)容進(jìn)行爬取

from lxml import etree
selector = etree.HTML(html)
content = selector.xptah('path') #此處的path指的就是需要爬蟲的文件路徑
for item in content:
    print item

前面講到的requests通常也是配合lxml使用,首先使用requests獲取到網(wǎng)頁(yè)內(nèi)容,即html文檔,然后使用lxml中的xpath爬取我們所需要的內(nèi)容。例子如下:

#爬取豆瓣電影top250,并將電影名稱和評(píng)分打印出來(lái)
import requests
from lxml import etree

s = requests.Session() #開啟一個(gè)requests會(huì)話
for id in range(0, 251, 25):
    url = 'https://movie.douban.com/top250/?start-' + str(id)
    r = s.get(url) #返回是一個(gè)reponse對(duì)象
    r.encoding = 'utf-8'
    root = etree.HTML(r.content)
    items = root.xpath('//ol/li/div[@class="item"]')
    # print(len(items))
    for item in items:
        title = item.xpath('./div[@class="info"]//a/span[@class="title"]/text()')
        name = title[0].encode('gb2312', 'ignore').decode('gb2312')
        # rank = item.xpath('./div[@class="pic"]/em/text()')[0]
        rating = item.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]
        print(name, rating)

4. 大殺器scrapy

scrapy是一個(gè)為了爬取網(wǎng)站數(shù)據(jù),提取結(jié)構(gòu)性數(shù)據(jù)而編寫的應(yīng)用框架。 可以應(yīng)用在包括數(shù)據(jù)挖掘,信息處理或存儲(chǔ)歷史數(shù)據(jù)等一系列的程序中。我們需要知道的是,scrapy是一種集成框架,類似于request和xpath這些方法在scrapy都有集成。

(1)scrapy安裝

安裝scrapy前,需要先安裝lxml模塊,然后按照之前說(shuō)的方法進(jìn)行安裝就可以(我的電腦安裝的是anaconda集成環(huán)境)

(2)scrapy的結(jié)構(gòu)

Paste_Image.png

其中,不同模塊負(fù)責(zé)不同的任務(wù)分工。首先Scheduler發(fā)出請(qǐng)求(Requests),Downloader負(fù)責(zé)從互聯(lián)網(wǎng)上下載內(nèi)容,將下載好的內(nèi)容(Responses)交給Spiders進(jìn)行解析,解析完成后將內(nèi)容Item返回,當(dāng)然其中可能會(huì)涉及到對(duì)于解析后數(shù)據(jù)的進(jìn)一步處理,這個(gè)任務(wù)是在Pipeline中完成的。

(3)scrapy通常有兩種使用方式:

  • 直接在python腳本里定義一個(gè)爬取數(shù)據(jù)的類(參見爬蟲案例1,2,3)
  • 創(chuàng)建完整的scrapy項(xiàng)目(參見爬蟲案例4);創(chuàng)建命令為
    scrapy startproject xxx

創(chuàng)建完scrapy項(xiàng)目后,會(huì)在對(duì)應(yīng)的文件下生成如下結(jié)構(gòu):

YLA943`5WMORH9SNVD~D}EA.png

其中,
spiders文件夾下面是真正爬蟲的代碼;
items之前提到過(guò),是定義需要爬取的內(nèi)容;
pipelines是對(duì)爬取到的數(shù)據(jù)進(jìn)行的進(jìn)一步處理;
settings中主要是一些環(huán)境變量和配置。
另外,scrapy有提供兩個(gè)xpath選擇器,HtmlXPathSelector和XmlXPathSelector,一個(gè)用于html,一個(gè)用于xml,xpath選擇器有三個(gè)方法:

  • select(xpath): 返回一個(gè)相對(duì)于當(dāng)前選中節(jié)點(diǎn)的選擇器列表(一個(gè)xpath可能選到多個(gè)節(jié)點(diǎn))
  • extract(): 返回選擇器(列表)對(duì)應(yīng)的節(jié)點(diǎn)的字符串(列表,類型就是python中的list)
    -_ re(regex)_: 返回正則表達(dá)式匹配的字符串(分組匹配)列表

需要注意的是,如果爬取的頁(yè)面相對(duì)簡(jiǎn)單,爬取內(nèi)容較少,且不用對(duì)爬取到的數(shù)據(jù)做過(guò)多的后期處理,使用第一種,反之,使用第二種,當(dāng)然建立完整的scrapy項(xiàng)目肯定可以處理簡(jiǎn)單任務(wù)。

三、爬蟲案例

1. 想要爬取得內(nèi)容都在同一頁(yè)面

本實(shí)例中,我們通過(guò)scrapy爬取七月在線課程信息。

#scrapy runspider spider.py –o xxx.json(運(yùn)行時(shí)可以在命令窗口進(jìn)行)
import scrapy 
class JulyeduSpider(scrapy.Spider):
    name = "julyedu"
    start_urls = ['https://www.julyedu.com/category/index'] #開始爬取網(wǎng)址,是一個(gè)list列表

    # 定義解析頁(yè)面函數(shù)
    def parse(self, response):
        for julyedu_class in response.xpath('//div[@class="course_info_box"]'):
            print julyedu_class.xpath('a/h4/text()').extract_first()
            print julyedu_class.xpath('a/p[@class="course-info-tip"][1]/text()').extract_first()
            print julyedu_class.xpath('a/p[@class="course-info-tip"][2]/text()').extract_first()
            print response.urljoin(julyedu_class.xpath('a/img[1]/@src').extract_first())
            print "\n"

            # 返回函數(shù)值
            yield {
                'title':julyedu_class.xpath('a/h4/text()').extract_first(),
                'desc': julyedu_class.xpath('a/p[@class="course-info-tip"][1]/text()').extract_first(),
                'time': julyedu_class.xpath('a/p[@class="course-info-tip"][2]/text()').extract_first(),
                'img_url': response.urljoin(julyedu_class.xpath('a/img[1]/@src').extract_first())
            }

2. 想要爬去的內(nèi)容在多頁(yè),不同頁(yè)之間可以進(jìn)行人為拼接構(gòu)成(例如博客園

本實(shí)例中,我們利用scrapy爬取博客園中的信息,爬取內(nèi)容包括每條博文的標(biāo)題、鏈接、作者、評(píng)論等信息

class CnBlogSpider(scrapy.Spider):
    name = "cnblogs"
    allowed_domains = ["cnblogs.com"]
    start_urls = [ 'http://www.cnblogs.com/pick/#p%s' % p for p in xrange(1, 11)        ]

    #定義解析函數(shù)
    def parse(self, response):
        for article in response.xpath('//div[@class="post_item"]'):
            print article.xpath('div[@class="post_item_body"]/h3/a/text()').extract_first().strip()
            print response.urljoin(article.xpath('div[@class="post_item_body"]/h3/a/@href').extract_first()).strip()
            print article.xpath('div[@class="post_item_body"]/p/text()').extract_first().strip()
            print article.xpath('div[@class="post_item_body"]/div[@class="post_item_foot"]/a/text()').extract_first().strip()
            print response.urljoin(article.xpath('div[@class="post_item_body"]/div/a/@href').extract_first()).strip()
            print article.xpath('div[@class="post_item_body"]/div[@class="post_item_foot"]/span[@class="article_comment"]/a/text()').extract_first().strip()
            print article.xpath('div[@class="post_item_body"]/div[@class="post_item_foot"]/span[@class="article_view"]/a/text()').extract_first().strip()
            print ""

            yield {
                'title': article.xpath('div[@class="post_item_body"]/h3/a/text()').extract_first().strip(),
                'link': response.urljoin(article.xpath('div[@class="post_item_body"]/h3/a/@href').extract_first()).strip(),
                'summary': article.xpath('div[@class="post_item_body"]/p/text()').extract_first().strip(),
                'author': article.xpath('div[@class="post_item_body"]/div[@class="post_item_foot"]/a/text()').extract_first().strip(),
                'author_link': response.urljoin(article.xpath('div[@class="post_item_body"]/div/a/@href').extract_first()).strip(),
                'comment': article.xpath('div[@class="post_item_body"]/div[@class="post_item_foot"]/span[@class="article_comment"]/a/text()').extract_first().strip(),
                'view': article.xpath('div[@class="post_item_body"]/div[@class="post_item_foot"]/span[@class="article_view"]/a/text()').extract_first().strip(),
            }

3. 想要爬取的內(nèi)容存在頁(yè)面跳轉(zhuǎn)(例如騰訊社會(huì)新聞

class QQNewsSpider(scrapy.Spider):
    name = 'qqnews'
    start_urls = ['http://news.qq.com/society_index.shtml']

    def parse(self, response):
        for href in response.xpath('//*[@id="news"]/div/div/div/div/em/a/@href'):
            full_url = response.urljoin(href.extract())
            yield scrapy.Request(full_url, callback=self.parse_question) #調(diào)用scrapy中Request方法,對(duì)合并后的網(wǎng)址進(jìn)行分析,調(diào)用函數(shù)是parse_question

    #真正意義上解析頁(yè)面的函數(shù)
    def parse_question(self, response):
        print response.xpath('//div[@class="qq_article"]/div/h1/text()').extract_first()
        print response.xpath('//span[@class="a_time"]/text()').extract_first()
        print response.xpath('//span[@class="a_catalog"]/a/text()').extract_first()
        print "\n".join(response.xpath('//div[@id="Cnt-Main-Article-QQ"]/p[@class="text"]/text()').extract())
        print ""
        yield {
            'title': response.xpath('//div[@class="qq_article"]/div/h1/text()').extract_first(),
            'content': "\n".join(response.xpath('//div[@id="Cnt-Main-Article-QQ"]/p[@class="text"]/text()').extract()),
            'time': response.xpath('//span[@class="a_time"]/text()').extract_first(),
            'cate': response.xpath('//span[@class="a_catalog"]/a/text()').extract_first(),
        }

4. 通過(guò)創(chuàng)建scrapy工程的方式爬取全國(guó)34個(gè)省、市所屬的2290個(gè)地區(qū)的歷史天氣預(yù)報(bào)數(shù)據(jù),網(wǎng)址請(qǐng)戳這里,并將其保存為json格式

之前跟大家分享的案例大多是參照網(wǎng)絡(luò)視頻資源和相關(guān)博客資料,這兩天由于項(xiàng)目需要,爬取全國(guó)34個(gè)省、市所屬的2290個(gè)地區(qū)的歷史天氣預(yù)報(bào)數(shù)據(jù),真正動(dòng)手才發(fā)現(xiàn)“紙上得來(lái)終覺(jué)淺,絕知此事要躬行”的道理所在,整個(gè)過(guò)程碰到很多坑,也請(qǐng)教了一些牛人,終于將數(shù)據(jù)成功爬取到本地,在此記錄下整個(gè)爬取過(guò)程。

1. 多級(jí)頁(yè)面跳轉(zhuǎn)問(wèn)題

涉及到多級(jí)頁(yè)面跳轉(zhuǎn)才能爬取到數(shù)據(jù)的場(chǎng)景,有兩個(gè)方面是需要特別注意的,第一是確保整個(gè)頁(yè)面跳轉(zhuǎn)過(guò)程的邏輯正確,第二是跳轉(zhuǎn)到某個(gè)具體頁(yè)面使用xpath進(jìn)行路經(jīng)查詢時(shí),要保證xpath的寫的沒(méi)有問(wèn)題。

2. Scrapy終端(Scrapy shell)

Scrapy終端是一個(gè)交互終端,供您在未啟動(dòng)spider的情況下嘗試及調(diào)試您的爬取代碼。 其本意是用來(lái)測(cè)試提取數(shù)據(jù)的代碼,不過(guò)您可以將其作為正常的Python終端,在上面測(cè)試任何的Python代碼。
對(duì)于檢查xpath路徑查詢語(yǔ)言是否正確非常,舉個(gè)例子,我想要爬取某個(gè)城市2017年一月的天氣中的日期數(shù)據(jù),

Paste_Image.png

根據(jù)html中提供的路徑,我寫了如下的xpath表達(dá)式

day = sel.xpath('//div[@class="tqtongji2"]/ul[position()>1]/li[1]/a/text()').extract()

具體對(duì)不對(duì),能不能爬取到相對(duì)應(yīng)的日期數(shù)據(jù),我們就可以利用scrapy shell進(jìn)行檢查。

(1)首先在命令窗口啟動(dòng)scrapy shell,啟動(dòng)語(yǔ)句也很簡(jiǎn)單,如下

scrapy shell url
其中url表示想測(cè)試的網(wǎng)頁(yè)鏈接。

Paste_Image.png

(2)輸入需要檢查的xpath語(yǔ)句

Paste_Image.png

可以看到輸出結(jié)果中已經(jīng)正確提取出我們需要的日期數(shù)據(jù),從而也說(shuō)明我們寫的xpath路徑?jīng)]有問(wèn)題。

3. 爬蟲正式開始

(1)建立scrapy工程

利用前面講到的方法創(chuàng)建相應(yīng)的scrapy工程,在item.py中創(chuàng)建需要爬去的數(shù)據(jù)如下:

Paste_Image.png

(2)爬蟲spider腳本

我們打開需要爬取頁(yè)面的首頁(yè)如下,http://lishi.tianqi.com/,

Paste_Image.png

從頁(yè)面中我們可以看到,全國(guó)各縣區(qū)的城市按照A,B,C...Z順序排列,每個(gè)字母下面包含很多城市,比如字母A下面包含阿城等地方。且每一類下面的第一個(gè)li標(biāo)簽是不需要的,因?yàn)榈谝粋€(gè)li標(biāo)簽表示的是字母A,B,C...Z等,如下圖

Paste_Image.png

分析到這一步,我們可以寫出一級(jí)解析函數(shù)parse來(lái)獲取所有城市—鏈接和城市名的xpath路徑查詢語(yǔ)言,

鏈接如下:

sel = Selector(response)
country_urls = sel.xpath('//ul[@class="bcity"]/li[position()>1]/a/@href').extract() 

城市名如下:

sel = Selector(response)
country_urls = sel.xpath('//ul[@class="bcity"]/li[position()>1]/a/text()').extract() 

接下來(lái)就是每個(gè)城市(鏈接)進(jìn)行for循環(huán)遍歷,將每個(gè)城市的鏈接url和城市名城保存到item中,保存file_name目的在于為了待會(huì)兒寫入數(shù)據(jù)時(shí)方便。將所有獲取到的城市鏈接和城市名保存到items列表中,然后使用for循環(huán)對(duì)每個(gè)城市的進(jìn)行二級(jí)頁(yè)面解析,調(diào)用的是scrapy的Request方法,Request中的回調(diào)函數(shù)callback就是二級(jí)頁(yè)面解析函數(shù)second_parse。一級(jí)解析函數(shù)parse的完整代碼如下:

Paste_Image.png

既然說(shuō)到二級(jí)頁(yè)面,我們還是首先觀察下二級(jí)頁(yè)面的特點(diǎn),以澳門歷史天氣詳情為例

Paste_Image.png

可以看到,澳門所有歷史數(shù)據(jù)(按月)都在div class = "tqtongji" 標(biāo)簽下面,每年的數(shù)據(jù)又被一個(gè)ul標(biāo)簽包圍,每個(gè)ul標(biāo)簽下面擁有很多個(gè)li標(biāo)簽,分別表示一年的各個(gè)月份數(shù)據(jù),分析到此,我們同樣可以在二級(jí)解析頁(yè)面函數(shù)中寫出獲取每個(gè)城市每個(gè)月鏈接和月份名稱的xpath路徑

鏈接如下:

sel = Selector(response)
month_urls = sel.xpath('//div[@class="tqtongji1"]/ul/li/a/@href').extract()

城市名如下:

sel = Selector(response)
month_titles = sel.xpath('//div[@class="tqtongji1"]/ul/li/a/text()').extract()

同樣,獲取到每個(gè)城市每個(gè)月份的鏈接后,在二級(jí)解析函數(shù)里面對(duì)每個(gè)月份進(jìn)行遍歷,最后仍然使用scrapy.Request對(duì)每個(gè)獲取的月份鏈接進(jìn)行解析,回調(diào)函數(shù)是三級(jí)頁(yè)面解析函數(shù)detail_parse。
以下是二級(jí)頁(yè)面解析函數(shù)的腳本

Paste_Image.png

最后跳轉(zhuǎn)到我們最終要爬取數(shù)據(jù)的頁(yè)面了,到了這一頁(yè)面之后(如下圖),便能夠很方便的爬取到我們需要的數(shù)據(jù)。

Paste_Image.png

直接貼上最終三級(jí)頁(yè)面解析函數(shù)

Paste_Image.png

到此,爬取數(shù)據(jù)的spider腳本已經(jīng)全部開發(fā)完成,不過(guò)為了將數(shù)據(jù)按照城市分別保存到本地,還需要在pipeline中進(jìn)行相應(yīng)設(shè)置如下:

Paste_Image.png

最終爬取的效果圖如下圖:

Paste_Image.png
Paste_Image.png

喜歡的朋友請(qǐng)小小的點(diǎn)個(gè)贊,你的肯定會(huì)讓我更有動(dòng)力?。?!

最后編輯于
?著作權(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)容