一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

如何用 Python 爬取網(wǎng)頁(yè)制作電子書

 寬帶連接 2018-01-27

關(guān)鍵時(shí)刻,第一時(shí)間送達(dá)!

作者簡(jiǎn)介:孫亖,軟件工程師,長(zhǎng)期從事企業(yè)信息化系統(tǒng)的研發(fā)工作,主要擅長(zhǎng)后臺(tái)業(yè)務(wù)功能的設(shè)計(jì)開發(fā)。

本文來(lái)自作者在 GitChat 上分享「如何用 Python 爬取網(wǎng)頁(yè)制作電子書」主題內(nèi)容。

有人爬取數(shù)據(jù)分析黃金周旅游景點(diǎn),有人爬取數(shù)據(jù)分析相親,有人大數(shù)據(jù)分析雙十一,連小學(xué)生寫論文都用上了大數(shù)據(jù)。

我們每個(gè)人每天都在往網(wǎng)上通過(guò)微信、微博、淘寶等上傳我們的個(gè)人信息,現(xiàn)在就連我們的錢都是放在網(wǎng)上,以后到強(qiáng)人工智能,我們連決策都要依靠網(wǎng)絡(luò)。網(wǎng)上的數(shù)據(jù)就是資源和寶藏,我們需要一把鏟子來(lái)挖掘它。

最近,AI 的興起讓 Python 火了一把。實(shí)際上 Python 擁有龐大的第三方支持,生態(tài)系統(tǒng)非常完整,可以適用各種場(chǎng)景和行業(yè)。

這次,我們準(zhǔn)備通過(guò) Python 學(xué)習(xí)爬蟲的開發(fā),既簡(jiǎn)單有趣,而且是數(shù)據(jù)采集重要一環(huán)。同時(shí)脫離應(yīng)用談技術(shù)就是耍流氓,通過(guò)制作電子書學(xué)習(xí)數(shù)據(jù)的收集與整理,即能學(xué)到東西又有實(shí)用價(jià)值。

我們將通過(guò)爬取網(wǎng)頁(yè)信息這個(gè)很小的應(yīng)用場(chǎng)景來(lái)體會(huì)數(shù)據(jù)預(yù)處理的思想,并從中學(xué)習(xí)了解數(shù)據(jù)處理中抓取、處理、分組、存儲(chǔ)等過(guò)程的實(shí)現(xiàn)。

我這次分享主要分為以下幾個(gè)部分:

  • Python 語(yǔ)法:通過(guò)分享掌握簡(jiǎn)單的 Python 開發(fā)語(yǔ)法和思路,側(cè)重于后面爬蟲開發(fā)的需要用的內(nèi)容;

  • Scrapy 爬蟲開發(fā):通過(guò)分享了解基本的 Scrapy 開發(fā),并實(shí)現(xiàn)從網(wǎng)絡(luò)爬取數(shù)據(jù),使用 Sigil 制作 epub 電子書;

  • 最后,我希望通過(guò)分享,讓更多人能夠入門并喜歡上 Python 開發(fā),掌握 Scrapy 爬蟲開發(fā)的思路和方法。

一、Python 開發(fā)

1.1 Windows 下環(huán)境安裝

熟悉 Windows 的安裝 Python 不難,首先官網(wǎng)下載:https://www./downloads/。

有兩個(gè)版本,根據(jù)需要選擇自己的版本,現(xiàn)在越來(lái)越多的庫(kù)開始支持 3,所以建議下載 3,這里我們以 2 為例。

雙擊下載的安裝文件,一路 Next 即可,但是要注意勾選 __pip__ 和 Add python.exe to Path:

pip 是 Python 生態(tài)體系里面的包管理工具,很多第三方庫(kù)可以通過(guò)它方便的管理。

安裝 Finish 之后,打開命令行窗口,輸入 Python:

如果出現(xiàn)這個(gè)界面說(shuō)明安裝成功了,如果出現(xiàn)下面的情況:

‘python’ 不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件。

需要把 python.exe 的目錄添加到 path 中,一般是 C:/Python27。

1.2 Python 之 HelloWorld

目前我所接觸過(guò)的所有編程語(yǔ)言都只要掌握三個(gè)內(nèi)容就可以了:就是輸入、處理、輸出。我們已經(jīng)安裝好了 Python,可以來(lái)一個(gè)最俗套的程序。

首先我們打開 windows 的控制臺(tái),然后輸入 python 回車,然后輸入如下代碼:

print ''Hello world!''

我就問(wèn)你俗不俗,好了,看結(jié)果:

根據(jù)我上面的說(shuō)法,這個(gè)程序的輸入就是 Hello World 字符串,處理使系統(tǒng)內(nèi)部的輸出處理,輸出結(jié)果就是 ‘Hello World’。

我們還可以把代碼寫在文件里面:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
print ''Hello World!''

執(zhí)行效果:

我們說(shuō)這個(gè)不是單純的秀一下,以前沒有用戶界面的時(shí)候 print 可以作為人機(jī)交互用途,現(xiàn)在多數(shù)是用于調(diào)試,可以在程序運(yùn)行的時(shí)候快速的輸出程序結(jié)果或者過(guò)程結(jié)果。

1.3 做菜與編程

現(xiàn)在有個(gè)很有意思的說(shuō)法:生數(shù)據(jù)(原始數(shù)據(jù))就是沒有處理過(guò)的數(shù)據(jù),熟數(shù)據(jù)(Cooked Data)是指原始數(shù)據(jù)經(jīng)過(guò)加工處理后的數(shù)據(jù),處理包括解壓縮、組織,或者是分析和提出,以備將來(lái)使用。

這就像做菜生菜是輸入,菜譜是程序,洗、切、烹飪等處理是程序執(zhí)行過(guò)程,最后輸出的熟菜。但不管生菜、熟菜都是菜,或者都是物質(zhì)。

準(zhǔn)備食材

在程序世界里的物質(zhì)組成就是數(shù)據(jù),就像有蘿卜白菜等不同的品種一樣,數(shù)據(jù)也有不同的類型。我目前所接觸到的數(shù)據(jù)類型主要有以下幾種:

  • 物理類:數(shù)據(jù)在物理內(nèi)存中的表達(dá)存儲(chǔ)方式;

  • 字節(jié)

  • 數(shù)據(jù)類:數(shù)據(jù)類中的具體類型代表了不同精度和內(nèi)存中不同的存儲(chǔ)結(jié)構(gòu);

  • 整數(shù)

  • 浮點(diǎn)數(shù)

  • 長(zhǎng)整型

  • 雙精度

  • 字符類:就是文本字符相關(guān)的數(shù)據(jù)類型;

  • 字符

  • 字符串

  • 邏輯類:就是邏輯真與邏輯假;

  • 布爾值

  • 復(fù)合類:由各基本的數(shù)據(jù)類型按照一定的結(jié)構(gòu)組合而成的數(shù)據(jù);

  • 結(jié)構(gòu)體

  • 集合

  • 字典

  • 列表

  • 序列

  • Hash 表

  • ……

這里我強(qiáng)調(diào)幾點(diǎn):

  • 首先,這個(gè)分類不是某種語(yǔ)言特有,目前大多數(shù)編程語(yǔ)言都差不多,你理解這個(gè)思想就把自己的編程能力擴(kuò)展了。

  • 其次,它不需要專門記憶,編程是程序性的知識(shí),運(yùn)用的知識(shí),是一種技能,你要做什么菜,你來(lái)這個(gè)分類查查需要什么原材料,再去具體研究,慢慢就會(huì)了,不做你記住了也沒用。

  • 用多深,研究多深,不用就別研究浪費(fèi)時(shí)間。比如說(shuō),我們一般性應(yīng)用不會(huì)去考慮數(shù)據(jù)的內(nèi)存模型,但是涉及到精度、性能或者邊界值時(shí)我們就需要小心,研究得深一些。

器皿

食材已準(zhǔn)備好了,可以下鍋,可鍋在哪里,你不能放在手里加工。程序里我們用變量、常量來(lái)盛各種數(shù)據(jù),還有個(gè)作用域的問(wèn)題,嚴(yán)格的廚房紅案和白案是分開的,有時(shí)候砧板是不能互用的。

  • 空值:四大皆空,什么也不是,不是 0,不是長(zhǎng)度為 0 的字符串,不是 false,什么都不是;

  • 變量:學(xué)過(guò)數(shù)學(xué)的人都應(yīng)該有這個(gè)概念,反正差不多;

  • 常量:固定不變的量,比如說(shuō) π。

烹飪手法

剛查了下,我大天朝常用的烹飪手法多達(dá) 20 多種,我歸納了一下,編程大概就那么幾種:

  • 數(shù)值計(jì)算——加減乘除、位移等;

  • 邏輯計(jì)算——邏輯真假判斷;

  • 過(guò)程計(jì)算——循環(huán)、嵌套、遞歸等;

  • 數(shù)據(jù)處理——字符串、對(duì)象的操作。

菜譜與炒菜

菜都準(zhǔn)備好了,下鍋怎么炒,全靠菜譜,它就是程序,而我們按照菜譜炒菜這個(gè)過(guò)程就是程序的執(zhí)行。

Python 或任何一種編程語(yǔ)言都是博大精深,同時(shí)又是一種技能,不可能在使用之前完全掌握,也沒必要。

我們需要知道的是我們想吃什么(程序要輸出什么),然后再去菜市場(chǎng)買時(shí)才找菜譜(搜索引擎查資料),最后按照我們的需求加工(編程)。

1.4 Python 簡(jiǎn)單實(shí)踐

首先我們來(lái)寫三個(gè) Python 文件:

hello.py

——事情的處理有落點(diǎn),程序執(zhí)行有入口,例如:main,這個(gè)文件可以看作程序的入口。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pkg
print ''Hello World!''
pkg.test()
p = pkg.Person(''Mike'', 23)
p.showInfo()

pkg.py

——程序可以分塊編寫,這樣層次更分明,易于理解和維護(hù),我們?cè)?pkg.py 中編寫一部分功能,作為演示模塊。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
def test():
   print ''Here is pkg''s test''
class Person(object):
   def __init__(self, name, age):
       self.name = name
       self.age = age
       pass
   def showInfo(self):
       print self.name
       print self.age

init.py

——這是一個(gè)空文件,也可以寫代碼,表明當(dāng)前路徑是包。

接下來(lái),我們來(lái)運(yùn)行一下:

python hello.py

顯示結(jié)果如下:

Hello World!
Here is pkg’s test
Mike
23

我們運(yùn)行了 hello.py 文件,然后 hello.py 導(dǎo)入了包 pkg;包 pkg 定義了一個(gè)方法和一個(gè)類,我們?cè)?hello.py 文件里面調(diào)用了外部的方法和類。

二、使用 Scrapy 抓取電子書

2.1 寫在爬取數(shù)據(jù)之前

雖然我們這里的數(shù)據(jù)都是從公開的網(wǎng)絡(luò)獲取,但也不能確定其版權(quán)問(wèn)題,因此獲取的數(shù)據(jù)僅用于編程練習(xí),嚴(yán)禁分享或用于其他用途。

好了,現(xiàn)在我們找一個(gè)在線看書的網(wǎng)站,找一本書把它下載到本地。首先,我們準(zhǔn)備下載工具,就是 Python 的爬蟲框架 Scrapy。

2.2 Scrapy 安裝

安裝完 Python 后可以用以下的命令按照 Scrapy,有些版本的 Python 沒有帶 pip 需要手動(dòng)安裝。

pip install scrapy

pip 是 Python 的包管理器,大量的第三方包或者說(shuō)功能可以通過(guò)這個(gè)工具來(lái)管理,所謂包就是模塊化的功能集合,基本的技術(shù)參考實(shí)踐里面的包。

我安裝成功顯示如下信息:

> Collecting scrapy
 Downloading Scrapy-1.5.0-py2.py3-none-any.whl (251kB)
   100% |████████████████████████████████| 256kB 181kB/s
Collecting service-identity (from scrapy)
 Downloading service_identity-17.0.0-py2.py3-none-any.whl
Collecting parsel>=1.1 (from scrapy)
 Downloading parsel-1.3.1-py2.py3-none-any.whl
Collecting six>=1.5.2 (from scrapy)
 Downloading six-1.11.0-py2.py3-none-any.whl
Collecting w3lib>=1.17.0 (from scrapy)
 Downloading w3lib-1.18.0-py2.py3-none-any.whl
Collecting lxml (from scrapy)
 Downloading lxml-4.1.1-cp27-cp27m-win_amd64.whl (3.6MB)
   100% |████████████████████████████████| 3.6MB 142kB/s
Collecting Twisted>
=13.1.0 (from scrapy)
 Downloading Twisted-17.9.0-cp27-cp27m-win_amd64.whl (3.2MB)
   100% |████████████████████████████████| 3.2MB 169kB/s
Collecting pyOpenSSL (from scrapy)
 Downloading pyOpenSSL-17.5.0-py2.py3-none-any.whl (53kB)
   100% |████████████████████████████████| 61kB 313kB/s
Collecting PyDispatcher>
=2.0.5 (from scrapy)
 Downloading PyDispatcher-2.0.5.tar.gz
Collecting queuelib (from scrapy)
 Downloading queuelib-1.4.2-py2.py3-none-any.whl
Collecting cssselect>
=0.9 (from scrapy)
 Downloading cssselect-1.0.3-py2.py3-none-any.whl
Collecting pyasn1 (from service-identity->scrapy)
 Downloading pyasn1-0.4.2-py2.py3-none-any.whl (71kB)
   100% |████████████████████████████████| 71kB 328kB/s
Collecting attrs (from service-identity->scrapy)
 Downloading attrs-17.4.0-py2.py3-none-any.whl
Collecting pyasn1-modules (from service-identity->scrapy)
 Downloading pyasn1_modules-0.2.1-py2.py3-none-any.whl (60kB)
   100% |████████████████████████████████| 61kB 347kB/s
Collecting hyperlink>
=17.1.1 (from Twisted>=13.1.0->scrapy)
 Downloading hyperlink-17.3.1-py2.py3-none-any.whl (73kB)
   100% |████████████████████████████████| 81kB 407kB/s
Collecting Automat>=0.3.0 (from Twisted>=13.1.0->scrapy)
 Downloading Automat-0.6.0-py2.py3-none-any.whl
Collecting constantly>=15.1 (from Twisted>=13.1.0->scrapy)
 Downloading constantly-15.1.0-py2.py3-none-any.whl
Collecting zope.interface>=3.6.0 (from Twisted>=13.1.0->scrapy)
 Downloading zope.interface-4.4.3-cp27-cp27m-win_amd64.whl (137kB)
   100% |████████████████████████████████| 143kB 279kB/s
Collecting incremental>=16.10.1 (from Twisted>=13.1.0->scrapy)
 Downloading incremental-17.5.0-py2.py3-none-any.whl
Collecting cryptography>=2.1.4 (from pyOpenSSL->scrapy)
 Downloading cryptography-2.1.4-cp27-cp27m-win_amd64.whl (1.3MB)
   100% |████████████████████████████████| 1.3MB 220kB/s
Requirement already satisfied: setuptools in c:\python27\lib\site-packages (from zope.interface>=3.6.0->Twisted>=13.1.0->scrapy)
Collecting idna>=2.1 (from cryptography>=2.1.4->pyOpenSSL->scrapy)
 Downloading idna-2.6-py2.py3-none-any.whl (56kB)
   100% |████████████████████████████████| 61kB 311kB/s
Collecting cffi>=1.7; platform_python_implementation != ''PyPy'' (from cryptography>=2.1.4->pyOpenSSL->scrapy)
 Downloading cffi-1.11.2-cp27-cp27m-win_amd64.whl (163kB)
   100% |████████████████████████████████| 163kB 183kB/s
Collecting enum34; python_version <>''3'' (from cryptography>=2.1.4->pyOpenSSL->scrapy)
 Downloading enum34-1.1.6-py2-none-any.whl
Collecting asn1crypto>=0.21.0 (from cryptography>=2.1.4->pyOpenSSL->scrapy)
 Downloading asn1crypto-0.24.0-py2.py3-none-any.whl (101kB)
   100% |████████████████████████████████| 102kB 194kB/s
Collecting ipaddress; python_version <>''3'' (from cryptography>=2.1.4->pyOpenSSL->scrapy)
 Downloading ipaddress-1.0.19.tar.gz
Collecting pycparser (from cffi>=1.7; platform_python_implementation != ''PyPy''->cryptography>=2.1.4->pyOpenSSL->scrapy)
 Downloading pycparser-2.18.tar.gz (245kB)
   100% |████████████████████████████████| 256kB 264kB/s
Installing collected packages: pyasn1, six, idna, pycparser, cffi, enum34, asn1crypto, ipaddress, cryptography, pyOpenSSL, attrs, pyasn1-modules, service-identity, w3lib, cssselect, lxml, parsel, hyperlink, Automat, constantly, zope.interface, incremental, Twisted, PyDispatcher, queuelib, scrapy
 Running setup.py install for pycparser ... done
 Running setup.py install for ipaddress ... done
 Running setup.py install for PyDispatcher ... done
Successfully installed Automat-0.6.0 PyDispatcher-2.0.5 Twisted-17.9.0 asn1crypto-0.24.0 attrs-17.4.0 cffi-1.11.2 constantly-15.1.0 cryptography-2.1.4 cssselect-1.0.3 enum34-1.1.6 hyperlink-17.3.1 idna-2.6 incremental-17.5.0 ipaddress-1.0.19 lxml-4.1.1 parsel-1.3.1 pyOpenSSL-17.5.0 pyasn1-0.4.2 pyasn1-modules-0.2.1 pycparser-2.18 queuelib-1.4.2 scrapy-1.5.0 service-identity-17.0.0 six-1.11.0 w3lib-1.18.0 zope.interface-4.4.3

2.3 新建 Scrapy 爬蟲項(xiàng)目

Scrapy 是 Python 程序,同時(shí)也是一套框架,提供了一系列工具來(lái)簡(jiǎn)化開發(fā),因此我們按照 Scrapy 的模式來(lái)開發(fā),先新建一個(gè) Scrapy 項(xiàng)目,如下:

scrapy startproject ebook

Scrapy 項(xiàng)目包含一些基礎(chǔ)框架代碼,我們?cè)诖嘶A(chǔ)上開發(fā),目錄結(jié)構(gòu)類似下圖:

2.4 新建 Scrapy 爬蟲

這時(shí),Scrapy 還不知道我們要爬取什么數(shù)據(jù),所以我們要用 Scrapy 工具新建一個(gè)爬蟲,命令如下:

scrapy genspider example example.com

下面實(shí)操,我們?cè)谄瘘c(diǎn)中文網(wǎng)找一篇免費(fèi)小說(shuō)的完本,這里選擇是《修真小主播》。

我們就在前面建立的 Scrapy 項(xiàng)目 ebook 下新建一個(gè)爬蟲,命令如下:

cd ebook
scrapy genspider xzxzb qidian.com

執(zhí)行成功之后,在項(xiàng)目的 spider 目錄下就多了一個(gè) xzxzb.py 的文件。

2.5 爬蟲思路

怎么抓取數(shù)據(jù),首先我們要看從哪里取,打開《修真小主播》的頁(yè)面,如下:

有個(gè)目錄頁(yè)簽,點(diǎn)擊這個(gè)頁(yè)簽可以看見目錄,使用瀏覽器的元素查看工具,我們可以定位到目錄和每一章節(jié)的相關(guān)信息,根據(jù)這些信息我們就可以爬取到具體的頁(yè)面:

2.6 獲取章節(jié)地址

現(xiàn)在我們打開 xzxzb.py 文件,就是我們剛剛創(chuàng)建的爬蟲:

# -*- coding: utf-8 -*-
import scrapy
class XzxzbSpider(scrapy.Spider):
   name = ''xzxzb''
   allowed_domains = [''qidian.com'']
   start_urls = [''http://qidian.com/'']
   def parse(self, response):
       pass

start_urls 就是目錄地址,爬蟲會(huì)自動(dòng)爬這個(gè)地址,然后結(jié)果就在下面的 parse 中處理?,F(xiàn)在我們就來(lái)編寫代碼處理目錄數(shù)據(jù),首先爬取小說(shuō)的主頁(yè),獲取目錄列表:

  def parse(self, response):
       pages = response.xpath(''//div[@id=''j-catalogWrap'']//ul[@class=''cf'']/li'')
       for page in pages:
           url = page.xpath(''./child::a/attribute::href'').extract()
           print url
       pass

獲取網(wǎng)頁(yè)中的 DOM 數(shù)據(jù)有兩種方式,一種是使用 CSS 選擇子,另外一種是使用 XML 的 xPath 查詢。

這里我們用 xPath,相關(guān)知識(shí)請(qǐng)自行學(xué)習(xí),看以上代碼,首先我們通過(guò) ID 獲取目錄框,獲取類 cf 獲取目錄列表:

pages = response.xpath(''//div[@id=''j-catalogWrap'']//ul[@class=''cf'']/li'')

接著,遍歷子節(jié)點(diǎn),并查詢 li 標(biāo)簽內(nèi) a 子節(jié)點(diǎn)的 href 屬性,最后打印出來(lái):

for page in pages:
           url = page.xpath(''./child::a/attribute::href'').extract()
           print url

這樣,可以說(shuō)爬取章節(jié)路徑的小爬蟲就寫好了,使用如下命令運(yùn)行 xzxzb 爬蟲查看結(jié)果:

scrapy crawl xzxzb

這個(gè)時(shí)候我們的程序可能會(huì)出現(xiàn)如下錯(cuò)誤:


ImportError: No module named win32api

運(yùn)行下面的語(yǔ)句即可:

pip install pypiwin32

屏幕輸出如下:

> ...
> [u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/wrrduN6auIlOBDFlr9quQA2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Jh-J5usgyW62uJcMpdsVgA2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/5YXHdBvg1ImaGfXRMrUjdw2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/fw5EBeKat-76ItTi_ILQ7A2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/KsFh5VutI6PwrjbX3WA1AA2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/-mpKJ01gPp1p4rPq4Fd4KQ2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/MlZSeYOQxSPM5j8_3RRvhw2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/5TXZqGvLi-3M5j8_3RRvhw2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/sysD-JPiugv4p8iEw--PPw2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/xGckZ01j64-aGfXRMrUjdw2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/72lHOJcgmedOBDFlr9quQA2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/cZkHZEYnPl22uJcMpdsVgA2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/vkNh45O3JsRMs5iq0oQwLQ2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/ge4m8RjJyPH6ItTi_ILQ7A2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Y33PuxrKT4dp4rPq4Fd4KQ2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/MDQznkrkiyXwrjbX3WA1AA2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/A2r-YTzWCYj6ItTi_ILQ7A2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Ng9CuONRKei2uJcMpdsVgA2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Q_AxWAge14pMs5iq0oQwLQ2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/ZJshvAu8TVVp4rPq4Fd4KQ2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/hYD2P4c5UB2aGfXRMrUjdw2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/muxiWf_jpqTgn4SMoDUcDQ2'']
[u''//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/OQQ5jbADJjVp4rPq4Fd4KQ2'']
> ...

爬取章節(jié)路徑的小爬蟲就寫好了,但我們的目的不僅于此,我們接下來(lái)使用這些地址來(lái)抓取內(nèi)容:

2.7 章節(jié)頁(yè)面分析

我們接下來(lái)分析一下章節(jié)頁(yè)面,從章節(jié)頁(yè)面我們要獲取標(biāo)題和內(nèi)容。

如果說(shuō)章節(jié)信息爬取使用的 parser 方法,那么我們可以給每一個(gè)章節(jié)內(nèi)容的爬取寫一個(gè)方法,比如:parser_chapter,先看看章節(jié)頁(yè)面的具體情況:

可以看到,章節(jié)的整個(gè)內(nèi)容在類名為 main-text-wrap 的 div 標(biāo)簽內(nèi),標(biāo)題是其中類名為j_chapterName的 h3 標(biāo)簽,具體內(nèi)容是類名為read-content j_readContent的 div 標(biāo)簽。

試著把這些內(nèi)容打印出來(lái):

# -*- coding: utf-8 -*-
import scrapy
class XzxzbSpider(scrapy.Spider):
   name = ''xzxzb''
   allowed_domains = [''qidian.com'']
   start_urls = [''https://book.qidian.com/info/1010780117/'']
   def parse(self, response):
       pages = response.xpath(''//div[@id=''j-catalogWrap'']//ul[@class=''cf'']/li'')
       for page in pages:
           url = page.xpath(''./child::a/attribute::href'').extract_first()
           # yield scrapy.Request(''https:'' + url, callback=self.parse_chapter)
           yield response.follow(url, callback=self.parse_chapter)
       pass
   def parse_chapter(self, response):
       title = response.xpath(''//div[@class=''main-text-wrap'']//h3[@class=''j_chapterName'']/text()'').extract_first().strip()
       content = response.xpath(''//div[@class=''main-text-wrap'']//div[@class=''read-content j_readContent'']'').extract_first().strip()
       print title
       # print content
       pass

上一步,我們獲取到了一個(gè)章節(jié)地址,從輸出內(nèi)容來(lái)看是相對(duì)路徑,因此我們使用了yield response.follow(url, callback=self.parse_chapter),第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),用來(lái)處理章節(jié)頁(yè)面,爬取到章節(jié)頁(yè)面后我們解析頁(yè)面和標(biāo)題保存到文件。

next_page = response.urljoin(url)
yield scrapy.Request(next_page, callback=self.parse_chapter)

scrapy.Request 不同于使用 response.follow,需要通過(guò)相對(duì)路徑構(gòu)造出絕對(duì)路徑,response.follow 可以直接使用相對(duì)路徑,因此就不需要調(diào)用 urljoin 方法了。

注意,response.follow 直接返回一個(gè) Request 實(shí)例,可以直接通過(guò) yield 進(jìn)行返回。

數(shù)據(jù)獲取了之后是存儲(chǔ),由于我們要的是 html 頁(yè)面,因此,我們就按標(biāo)題存儲(chǔ)即可,代碼如下:

  def parse_chapter(self, response):
       title = response.xpath(''//div[@class=''main-text-wrap'']//h3[@class=''j_chapterName'']/text()'').extract_first().strip()
       content = response.xpath(''//div[@class=''main-text-wrap'']//div[@class=''read-content j_readContent'']'').extract_first().strip()
       # print title
       # print content
       filename = ''./down/%s.html'' % (title)
       with open(filename, ''wb'') as f:
           f.write(content.encode(''utf-8''))
       pass

至此,我們已經(jīng)成功的抓取到了我們的數(shù)據(jù),但還不能直接使用,需要整理和優(yōu)化。

2.8 數(shù)據(jù)整理

首先,我們爬取下來(lái)的章節(jié)頁(yè)面排序不是很好,如果人工去排需要太多的時(shí)間精力;另外,章節(jié)內(nèi)容包含許多額外的東西,閱讀體驗(yàn)不好,我們需要優(yōu)化內(nèi)容的排版和可讀性。

我們先給章節(jié)排個(gè)序,因?yàn)槟夸浿械恼鹿?jié)列表是按順序排列的,所以只需要給下載頁(yè)面名稱添加一個(gè)順序號(hào)就行了。

可是保存網(wǎng)頁(yè)的代碼是回調(diào)函數(shù),順序只是在處理目錄的時(shí)候能確定,回調(diào)函數(shù)怎么能知道順序呢?因此,我們要告訴回調(diào)函數(shù)它處理章節(jié)的順序號(hào),我們要給回調(diào)函數(shù)傳參,修改后的代碼是這樣的:

  def parse(self, response):
       pages = response.xpath(''//div[@id=''j-catalogWrap'']//ul[@class=''cf'']/li'')
       for page in pages:
           url = page.xpath(''./child::a/attribute::href'').extract_first()
           idx = page.xpath(''./attribute::data-rid'').extract_first()
           # yield scrapy.Request(''https:'' + url, callback=self.parse_chapter)
           req = response.follow(url, callback=self.parse_chapter)
           req.meta[''idx''] = idx
           yield req
       pass
   def parse_chapter(self, response):
       idx = response.meta[''idx'']
       title = response.xpath(''//div[@class=''main-text-wrap'']//h3[@class=''j_chapterName'']/text()'').extract_first().strip()
       content = response.xpath(''//div[@class=''main-text-wrap'']//div[@class=''read-content j_readContent'']'').extract_first().strip()
       # print title
       # print content
       filename = ''./down/%s_%s.html'' % (idx, title)
       cnt = ''

%s

%s''
% (title, content)
       with open(filename, ''wb'') as f:
           f.write(cnt.encode(''utf-8''))
       pass

不知道大家注意到?jīng)]有,前面的分析中目錄已經(jīng)提供了一個(gè)data_rid可以作為排序號(hào),我們?cè)谀夸浄治鲰?yè)面獲取這個(gè)序號(hào),然后通過(guò) request 的 meta 傳入parse_chapter。

在parse_chapter中通過(guò) response 的 meta 獲取傳入的參數(shù),然后文件名中加入這個(gè)順序好完成了排序。另外,Sigil 找那個(gè)通過(guò) H1 標(biāo)簽來(lái)生成目錄,需要目錄的話,我們需要給內(nèi)容添加一個(gè) h1 標(biāo)簽。

還有可讀性差的問(wèn)題,也許我們下載的網(wǎng)頁(yè)可能會(huì)包含一些亂七八糟的東西,我們有很多辦法,也可以使用 readbility 等第三方庫(kù),這里就不深入了。

三、使用 Sigil 制作電子書

電子書的制作,完全就是工具的應(yīng)用,非常簡(jiǎn)單,這里把流程過(guò)一下,大家根據(jù)興趣自行深入。

3.1 Sigil 簡(jiǎn)介

Sigil 是一個(gè)多平臺(tái)的 ePub 電子書編輯器。官方網(wǎng)站:https:///,下載頁(yè)面在 https://github.com/Sigil-Ebook/Sigil/releases,根據(jù)自己的需求下載,安裝很簡(jiǎn)單就不啰嗦了。

3.2 ePub 電子書簡(jiǎn)介

ePub(Electronic Publication 的縮寫,意為:電子出版),是一個(gè)自由的開放標(biāo)準(zhǔn),屬于一種可以 “自動(dòng)重新編排” 的內(nèi)容;也就是文字內(nèi)容可以根據(jù)閱讀設(shè)備的特性,以最適于閱讀的方式顯示。

ePub 檔案內(nèi)部使用了 XHTML 或 DTBook (一種由 DAISY Consortium 提出的 XML 標(biāo)準(zhǔn))來(lái)展現(xiàn)文字、并以 zip 壓縮格式來(lái)包裹檔案內(nèi)容。EPub 格式中包含了數(shù)位版權(quán)管理(DRM)相關(guān)功能可供選用。

3.3 加載 html 文件

要制作 ePub 電子書,我們首先通過(guò) Sigil 把我們的抓取的文件加載到程序中,在添加文件對(duì)話框中我們?nèi)x所有文件:

內(nèi)容都是 HTML 文件,所以編輯、排版什么的學(xué)習(xí)下 HTML。

3.4 制作目錄

文件中存在 HTML 的 h 標(biāo)簽時(shí),點(diǎn)擊生成目錄按鈕就可以自動(dòng)生成目錄,我們?cè)谇懊鏀?shù)據(jù)抓取時(shí)已經(jīng)自動(dòng)添加了 h1 標(biāo)簽:

3.5 制作封面

封面本質(zhì)上也是 HTML,可以編輯,也可以從頁(yè)面爬取,就留給大家自己實(shí)現(xiàn)吧。

3.6 編輯元數(shù)據(jù)

編輯書名、作者等信息:

3.6 輸出 ePub

編輯完成后保存,取個(gè)名字:

輸出可以使用電子書閱讀軟件打開查看,我用的是 Calibre,還可以方便的轉(zhuǎn)換為相應(yīng)的格式裝到 Kindle 中閱讀。

整個(gè)過(guò)程就結(jié)束了,文章內(nèi)代碼提交到碼云:https:///yjGizR,接下來(lái)自由發(fā)揮,請(qǐng)開始你的表演。

參考資料

爬蟲 Scrapy 學(xué)習(xí)系列之一:Tutorial:https:///LwqouP。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美一区二区三区视频区| 日韩精品视频高清在线观看| 日本深夜福利在线播放| 乱女午夜精品一区二区三区| 日韩欧美高清国内精品| 免费性欧美重口味黄色| 国产福利一区二区三区四区| 午夜视频在线观看日韩| 国产女性精品一区二区三区| 亚洲一区二区三区福利视频| 亚洲国产精品国自产拍社区| 免费福利午夜在线观看| 国产日韩欧美在线播放| 一区二区福利在线视频| 欧美午夜一级特黄大片| 欧美成人免费一级特黄| 好吊日成人免费视频公开| 国产不卡在线免费观看视频| 国产精品国三级国产专不卡| 91福利视频日本免费看看| 国产精品久久女同磨豆腐| 老富婆找帅哥按摩抠逼视频 | 日本一品道在线免费观看| 最好看的人妻中文字幕| 人妻中文一区二区三区| 91亚洲精品综合久久| 国产麻豆一线二线三线| 日本国产欧美精品视频| 亚洲欧美精品伊人久久| 久久亚洲国产视频三级黄| 日本精品视频一二三区| 欧美日韩国内一区二区| 国产日韩中文视频一区| 国产成人午夜福利片片| 黑鬼糟蹋少妇资源在线观看| 日本不卡一本二本三区| 国产亚洲精品俞拍视频福利区| 亚洲妇女黄色三级视频| 国产中文字幕一区二区| 免费一区二区三区少妇| 黑鬼糟蹋少妇资源在线观看|