這是日常學python的第15篇原創文章
前幾篇文章我們學習了requests庫和正則,還有個urllib庫,我上篇文章也用了requests庫來教大家去爬那些返回json格式的網頁,挺好玩的。有讀者讓我來個正則的,所以我今天就來個正則+requests來進行爬取。
今天原來是想爬小說的,但想到我不怎麼看小說,讀者也是都喜歡學習的,對吧?嘻嘻!所以我來爬個與python相關的內容,恰好前幾天我又看到別人推薦的一本python進階書,這本書的作者是我們的python大神kennethreitz徵集各路愛好python的人所寫的,下面是地址:
中文版:pythonguidecn.readthedocs.io/zh/latest/
英文版:docs.python-guide.org/en/latest/
這本書適合於一切有python的學習者,不管你是初入python的小白,還是熟練使用python的老手,都適用。但是不看也沒有影響你學習爬蟲哈,這個只是說些python的奇淫技巧。
由於這本書在網上只有英語的電子版,可我英語渣渣,所以爬箇中文版的網頁然後把他弄成電子版。
若想直接獲取該書電子版,可以在公眾號「日常學python」後臺回覆『進階』直接獲取。
本篇文章用到的工具如下:
requests庫
正規表示式
Sigil:將html網頁轉成epub電子書
epub轉pdf:http://cn.epubee.com/epub轉pdf.html
好了,下面詳細分析:
可以看到首頁中有整本書的內容連結,所以可以直接爬首頁獲取整本書的連結。
熟練地按下f12檢視網頁請求,非常容易找到這個
請求網站為:pythonguidecn.readthedocs.io/zh/latest/
請求方式為get,狀態碼為200,而且返回的是html元素,所以我們可以用正則來匹配所需要的內容。
那看看我們的匹配內容所在的地方
可以看到這個內容的地址和內容標題都在這個a標籤上,所以正則很容易,如下:
toctree-l1.*?reference internal" href="([^"]*?)">(.*?)</a>
複製程式碼
不知道你的正則學得怎樣了,這裡還是簡單說下:
.:這個是概括字符集,為匹配除換行符以外的任意字元
*:這個是數量詞,匹配的次數為0次以上
?:加了這個問號表示非貪婪,一般預設為貪婪
[^"]:這個表示不匹配雙引號,挺好用的
實在不記得的可以看看我這篇文章,這裡不詳細說了,不記得就點開爬蟲必學知識之正規表示式下篇看看
這裡需要注意的是:在這裡獲取的網址列表裡面有個內容的導航,如下:
所有我們在匹配完之後還需要再將這些帶#號的網址給過濾掉。
接下來的就是獲取每個網頁的內容
可以看到內容都在這個div標籤內,所以和上面一樣,用正則就可以獲取了。
ps: 其實這裡用BeautifulSoup更好用,我會在後面文章中講到哈!
匹配內容的正則為:
section".*?(<h1>.*?)<div class="sphinxsidebar
複製程式碼
因為我的那個工具是把這些內容的html下載下來就可以了,所以接下來不需要清洗裡面的html元素。
內容分析完畢,接下來的就容易了,就是用個迴圈把遍歷所有文章,然後就利用正則把他爬下來就可以了。
import re, requests
class Spider(object):
def __init__(self, headers, url):
self.headers = headers
self.url = url
def __get_hrefs(self):
'''獲取書本的所有連結'''
response = requests.get(self.url, self.headers)
if response.status_code == 200:
response.encoding = 'utf-8'
hrefs = re.findall('toctree-l1.*?reference internal" href="([^"]*?)">(.*?)</a>', response.text, re.S)
return hrefs
else:
print('訪問書本內容失敗,狀態碼為', response.status_code)
def __get_page(self, url):
'''獲取首頁'''
response = requests.get(url, self.headers)
response.encoding = 'utf-8'
content = re.findall('section".*?(<h1>.*?)<div class="sphinxsidebar', response.text, re.S)
return content[0]
def __get_content(self, href):
'''獲取每個頁面的內容'''
if href:
href = self.url + href
response = requests.get(href, self.headers)
response.encoding = 'utf-8'
content = re.findall('section".*?(<h1>.*?)<div class="sphinxsidebar', response.text, re.S)
if content:
return content[0]
else:
print('正則獲取失敗')
else:
print('獲取內容失敗')
def run(self):
'''迴圈獲取整本書內容'''
self.num = 0
hrefs = self.__get_hrefs()
content = self.__get_page(self.url)
with open(str(self.num)+'Python最佳實踐指南.html', 'w', encoding='utf-8') as f:
f.write(content)
print('寫入目錄成功')
for href, title in hrefs:
if "#" in href:
continue
self.num += 1
content = self.__get_content(href)
with open(str(self.num)+title+'.html', 'w', encoding='utf-8') as f:
f.write(content)
print('下載第'+str(self.num)+'章成功')
print('下載完畢')
def main():
url = 'http://pythonguidecn.readthedocs.io/zh/latest/'
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36'}
spider = Spider(headers, url)
spider.run()
if __name__ == '__main__':
main()
複製程式碼
點選執行,感覺美滋滋,可惜啊,程式碼總是愛玩弄你,趕緊報了個錯:
File "E:/anaconda/python_project/newspaper/spider.py", line 52, in run
with open(str(self.num)+title+'.html', 'w', encoding='utf-8') as f:
FileNotFoundError: [Errno 2] No such file or directory: '38與C/C++庫互動.html'
複製程式碼
一眼看下去,還挺鬱悶的,我沒有開啟檔案的,都是在寫檔案,為什麼報了這個錯?仔細一看報錯內容,這個名字有問題啊,你看
38與C/C++庫互動.html
複製程式碼
這個在window系統是以為你在 38與C 的 C++庫互動.html 下的,怪不得會報錯,所以,我在這裡加了這個程式碼把/給替換掉
點選Sigil 的 + 號把剛才下載的內容匯入
生成目錄
新增書名作者
新增封面:點選左上角的 工具 -> 新增封面 即可
點選儲存即可完成
轉pdf:cn.epubee.com/epub轉pdf.ht…
這個很容易就不說了。
結語
好了,文章內容就這麼多,下個文章就是學習新內容了。期待ing。
上述文章如有錯誤歡迎在留言區指出,如果這篇文章對你有用,點個贊,轉個發如何?
日常學python
程式碼不止bug,還有美和樂趣