Python--Scrapy爬蟲獲取簡書作者ID的全部文章列表數(shù)據(jù)

最近Python大火,為了跟上時(shí)代,試著自學(xué)了下。Scrapy是一個(gè)高級(jí)的Python爬蟲框架,它不僅包含了爬蟲的特性,還可以方便的將爬蟲數(shù)據(jù)保存到csv、json等文件中。

今天我們就試著用Scrapy來爬取簡書某位作者的全部文章。
在本篇教程中,我們假定您已經(jīng)安裝好Scrapy。 如若不然,請(qǐng)參考 安裝指南

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

在開始爬取之前,我們必須創(chuàng)建一個(gè)新的Scrapy項(xiàng)目,我這里命名為jianshu_article。打開Mac終端,cd到你打算存儲(chǔ)代碼的目錄中,運(yùn)行下列命令:

  //Mac終端運(yùn)行如下命令:
  scrapy startproject jianshu_article

2.創(chuàng)建爬蟲程序

  //cd到上面創(chuàng)建的文件目錄
  cd jianshu_article
  //創(chuàng)建爬蟲程序
  scrapy genspider jianshu jianshu.com
  /*
  文件說明:
    scrapy.cfg  項(xiàng)目的配置信息,主要為Scrapy命令行工具提供一個(gè)基礎(chǔ)的配置信息。(真正爬蟲相關(guān)的配置信息在settings.py文件中)
    items.py    設(shè)置數(shù)據(jù)存儲(chǔ)模型,用于結(jié)構(gòu)化數(shù)據(jù),如:Django的Model
    pipelines    數(shù)據(jù)處理行為,如:一般結(jié)構(gòu)化的數(shù)據(jù)持久化
    settings.py 配置文件,如:USER_AGENT(模擬瀏覽器,應(yīng)對(duì)網(wǎng)站反爬),遞歸的層數(shù)、并發(fā)數(shù),延遲下載等
    spiders      爬蟲目錄,如:創(chuàng)建文件,編寫爬蟲規(guī)則
  */

為了方便編寫程序,我們用Pycharm打開項(xiàng)目,執(zhí)行完上面的命令程序會(huì)自動(dòng)創(chuàng)建目錄及文件,其中生成了一個(gè)jianshu.py的文件,后面我們主要邏輯都將寫在此文件中。


jianshu.py

3.設(shè)置數(shù)據(jù)模型

雙擊items.py文件。
找到你想爬取的簡書作者首頁,如我自己的首頁http://www.lxweimin.com/u/6b14223f1b58,用谷歌瀏覽器打開,空白處鼠標(biāo)右擊,單擊“檢查”進(jìn)入控制臺(tái)開發(fā)者模式:

打開控制臺(tái).png

通過分析網(wǎng)頁源碼,我們大概需要這些內(nèi)容:

# -*- 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 JianshuArticalItem(scrapy.Item):
    avatar = scrapy.Field()     #頭像
    nickname = scrapy.Field()      #昵稱
    time = scrapy.Field()   #發(fā)表時(shí)間
    wrap_img = scrapy.Field()   #封面(缺省值)
    title = scrapy.Field()     #標(biāo)題
    abstract = scrapy.Field()   #正文部分顯示
    read = scrapy.Field()   #查看人數(shù)
    comments = scrapy.Field()   #評(píng)論數(shù)
    like = scrapy.Field()   #喜歡(點(diǎn)贊)
    detail = scrapy.Field()   #文章詳情url
    pass

如此數(shù)據(jù)模型就創(chuàng)建好了,后面運(yùn)行爬蟲的時(shí)候,我得到的數(shù)據(jù)將存進(jìn)模型對(duì)應(yīng)的位置。

4.分析網(wǎng)頁源碼,編寫爬蟲

因?yàn)楸救吮容^懶很少寫文章,文章數(shù)比較少,為了呈現(xiàn)分頁的效果,我在簡書選取了一位作者CC老師_MissCC的主頁進(jìn)行爬取。
我們通過分析URL可以找到一些特征:
作者的URL為:http://www.lxweimin.com/u/ + 作者ID:

作者主頁URL.png

文章的URL為:http://www.lxweimin.com/p/ + 文章ID:

文章URL.png

雖然我們?cè)跒g覽器直接打開作者的URL,鼠標(biāo)滾輪往下滾動(dòng)會(huì)動(dòng)態(tài)加載下一頁直至最后一篇文章URL還是保持不變。但是作為Scrapy爬蟲貌似只能拿到第一頁,那么如何做到呢?以我個(gè)人多年的開發(fā)經(jīng)驗(yàn)我嘗試在URL后面拼接一個(gè)"page"參數(shù)加上頁數(shù),果不其然,能請(qǐng)求到不同的數(shù)據(jù)。


拼接參數(shù)page拿到分頁數(shù)據(jù).png

找到這些規(guī)律,我們就可以通過分析HTML源碼,拿到我們想要的數(shù)據(jù)了。
首先,我們回到j(luò)ianshu.py這個(gè)文件,導(dǎo)入模型:

  //從項(xiàng)目名 jianshu_article的文件items.py導(dǎo)入JianshuArticleItem類
  from jianshu_article.items import JianshuArticleItem

設(shè)置必要參數(shù)發(fā)起首次請(qǐng)求:

 # -*- coding: utf-8 -*-
import scrapy
from jianshu_article.items import JianshuArticleItem


class JianshuSpider(scrapy.Spider):
    name = 'jianshu'
    allowed_domains = ['jianshu.com']

    user_id = "1b4c832fb2ca"
    url = "http://www.lxweimin.com/u/{0}?page=1".format(user_id)
    start_urls = [
        url,
    ]


    def parse(self, response):
        #用戶頭像
        c = response.xpath('//div[@class="main-top"]/a[@class="avatar"]/img/@src').extract_first()
        print(c)
        pass

至此終端運(yùn)行命令scrapy crawl jianshu,理論上可以打印網(wǎng)頁內(nèi)容。實(shí)則不然,沒有請(qǐng)求到任何數(shù)據(jù),終端會(huì)打印一些日志信息:


日志.png

不難發(fā)現(xiàn),報(bào)了403的問題和HTTP status code is not handled or not allowed的問題,導(dǎo)致"Closing spider (finished)"爬蟲終止。通過萬能百度,我知道大概是網(wǎng)站做了一些相應(yīng)的反爬蟲的措施導(dǎo)致的。對(duì)癥下藥,我們只需要在settings.py,做一些相應(yīng)修改就可以了:

```
User_Agent中文名為用戶代理,簡稱 UA,它是一個(gè)特殊字符串頭,使得服務(wù)器能夠識(shí)別客戶使用的
操作系統(tǒng)及版本、CPU 類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。
通俗點(diǎn)講,我們配置這個(gè)字段的目的就是為了偽裝成瀏覽器打開網(wǎng)頁,達(dá)到騙過目標(biāo)網(wǎng)站的監(jiān)測(cè)。
```
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'
CONCURRENT_REQUESTS = 1 #并發(fā)數(shù)
DOWNLOAD_DELAY = 5  #為了防止IP被封,我們5秒請(qǐng)求一次
HTTPERROR_ALLOWED_CODES = [403] #上面報(bào)的是403,就把403加入

#默認(rèn)為True,就是要遵守robots.txt 的規(guī)則,這里我們改為False
ROBOTSTXT_OBEY = False

做了相應(yīng)的修改,我們?cè)俅螆?zhí)行爬蟲命令:scrapy crawl jianshu ,看日志打印獲取到頭像。


獲取到頭像.png

既然網(wǎng)頁數(shù)據(jù)能爬取成功,我們后面要做的只是分析網(wǎng)頁源碼了,下面就不一一去分析了,體力活。當(dāng)然在此之前你要對(duì)xpath有一定的了解。

下面引用Scrapy中文官網(wǎng)介紹:
從網(wǎng)頁中提取數(shù)據(jù)有很多方法。Scrapy使用了一種基于 XPathCSS 表達(dá)式機(jī)制: Scrapy Selectors。 關(guān)于selector和其他提取機(jī)制的信息請(qǐng)參考 Selector文檔 。

這里給出XPath表達(dá)式的例子及對(duì)應(yīng)的含義:

  • /html/head/title: 選擇HTML文檔中 <head> 標(biāo)簽內(nèi)的 <title> 元素
  • /html/head/title/text(): 選擇上面提到的 <title> 元素的文字
  • //td: 選擇所有的 <td> 元素
  • //div[@class="mine"]: 選擇所有具有 class="mine" 屬性的 div 元素

上邊僅僅是幾個(gè)簡單的XPath例子,XPath實(shí)際上要比這遠(yuǎn)遠(yuǎn)強(qiáng)大的多。 如果您想了解的更多,我們推薦 這篇XPath教程
通過上面的介紹,相信你可以做接下來的爬蟲工作了,下面貼上jianshu.py的全部代碼,以供參考:

# -*- coding: utf-8 -*-
import scrapy
from jianshu_article.items import JianshuArticleItem


class JianshuSpider(scrapy.Spider):
    name = 'jianshu'
    allowed_domains = ['jianshu.com']
    user_id = "1b4c832fb2ca" #替換此用戶ID可獲取你需要的數(shù)據(jù),或者放開下一行的注釋
    #user_id = input('請(qǐng)輸入作者id:\n')
    url = "http://www.lxweimin.com/u/{0}?page=1".format(user_id)
    start_urls = [
        url,
    ]

    def parse(self, response):
        # [關(guān)注,粉絲,文章]
        a = response.xpath('//div[@class="main-top"]/div[@class="info"]/ul/li/div/a/p/text()').extract()
        print(a)
        # [字?jǐn)?shù),收獲喜歡]
        b = response.xpath('//div[@class="main-top"]/div[@class="info"]/ul/li/div/p/text()').extract()
        print(b)
        # 大頭像
        c = response.xpath('//div[@class="main-top"]/a[@class="avatar"]/img/@src').extract_first()
        print(c)
        # 用戶名
        d = response.xpath('//div[@class="main-top"]/div[@class="title"]/a/text()').extract_first()
        print(d)
        # 性別
        e = response.xpath('//div[@class="main-top"]/div[@class="title"]/i/@class').extract_first()
        print(e)

        # 獲取文章總數(shù),計(jì)算頁數(shù)。(簡書網(wǎng)站默認(rèn)每頁是9組數(shù)據(jù))
        temp = int(a[2])
        if (temp % 9 > 0):
            count = temp // 9 + 1
        else:
            count = temp // 9
        print("總共" + str(count) + "頁")

        base_url = "http://www.lxweimin.com/u/{0}?page={1}"
        for i in range(1, count + 1):
            i = count + 1 - i  #理論上正序1~count就是按順序獲取的,但是獲取的數(shù)據(jù)是倒置的,所以我們獲取count~1的數(shù)據(jù),得到的數(shù)組就是按照網(wǎng)頁形式1~count頁碼排序的了
            yield scrapy.Request(base_url.format(self.user_id, i), dont_filter=True, callback=self.parse_page)

    #迭代返回每頁的內(nèi)容
    def parse_page(self, response):
        for sel in response.xpath('//div[@id="list-container"]/ul/li'):
            item = JianshuArticleItem()
            item['wrap_img'] = sel.xpath('a/img/@src').extract_first()
            item['avatar'] = sel.xpath('div//a[@class="avatar"]/img/@src').extract_first()
            item['nickname'] = sel.xpath('div//a[@class="nickname"]/text()').extract_first()
            item['time'] = sel.xpath('div//span[@class="time"]/@data-shared-at').extract_first()
            item['title'] = sel.xpath('div/a[@class="title"]/text()').extract_first()
            item['abstract'] = sel.xpath('div/p[@class="abstract"]/text()').extract_first()
            item['read'] = sel.xpath('div/div[@class="meta"]/a[1]/text()').extract()[1]
            item['comments'] = sel.xpath('div/div[@class="meta"]/a[2]/text()').extract()[1]
            item['like'] = sel.xpath('div/div[@class="meta"]/span/text()').extract_first()
            item['detail'] = sel.xpath('div/a[@class="title"]/@href').extract_first()
            yield item

至此爬蟲代碼編寫完畢,如果要把獲取的數(shù)據(jù)保存下來,你可以終端執(zhí)行如下命令:

/*
此命令用于把爬取的數(shù)據(jù)保存為json文件格式,當(dāng)然你也可以保存為別的文件格式。
Scrapy官方列出的文件格式有如下幾種:('json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle')。
溫馨提示:如果要再次爬取,最好換一個(gè)文件名或者清空數(shù)據(jù)再爬取,因?yàn)榈诙€是寫入上一個(gè)文件,數(shù)據(jù)不會(huì)覆蓋,
會(huì)堆積在上次獲取的下面,造成json文件格式報(bào)錯(cuò)。
*/
scrapy crawl jianshu -o data.json

程序執(zhí)行完后,我們可以在文件目錄看到新生成的data.json文件,雙擊可以看到我們要獲取的全部數(shù)據(jù):

執(zhí)行爬蟲獲取到的數(shù)據(jù).png

json解析數(shù)據(jù)跟網(wǎng)站上的完全吻合.png

github地址:https://github.com/leesonp/jianshu_article
至此以上就是本文的全部內(nèi)容,謝謝閱讀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,441評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,475評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,834評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,009評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,559評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,516評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,728評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評(píng)論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,249評(píng)論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,484評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容