以下內容爲本人原創,歡迎大家觀看學習,禁止用於商業用途,轉載請說明出處,謝謝合作!
大噶好!我是python練習時長一個月的Yhen,今天我學習了爬取小說網站,特別感謝六星教育python學院,我就是在這裏學的,老師講的挺好挺仔細的,以下內容都是基於我在課堂上學到的,大家有興趣可以到騰訊課堂報名聽課,都是免費的。
接下來我把經驗分享給大家,作爲小白的我們,在寫代碼時肯定會遇到一些bug,下面有我敲代碼過程中出現的錯誤以及我的解決方法,希望可以幫助到大家!最後的源碼也會給大家!因爲比較詳細所以內容可能較多,大家如果只想知道結果,可以直接看源碼。
好啦咱們說幹就幹,敲起來!
今天我們我們要爬取的小說網站是“千千小說網”
url :https://www.qqxsw.co/
我們今天就做的是把首頁第一本書《牧龍師》裏面的內容爬下來
ok,清楚了需求,那我們馬上開動起來吧!
我們首先先對小說的主頁頁面進行請求
# 導入爬蟲包
import requests
# 小說頁面的url
url = 'https://www.qqxsw.co/book_107838/'
# 對小說頁面進行請求
response =requests.get(url).text
# 打印小說頁面源碼信息
print(response)
我們滿心歡喜地執行上面的代碼
我們得到了一堆數據,說明我們請求成功啦!
但是…有沒有發現上面的數據有點奇怪呢?
是的…他出現了亂碼
像這樣的數據,就是出現了中文亂碼
出現這種情況的原因是因爲頁面的編碼格式是“GBK”格式,而我們爬下來的數據默認是“utf-8”,所以和我們頁面編碼不一致而導致的。
關於“ignore”一開始我也不懂,
百度得知:因爲decode的函數原型是decode([encoding], [errors=‘strict’]),可以用第二個參數控制錯誤處理的策略,默認的參數就是strict,代表遇到非法字符時拋出異常;如果設置爲ignore,則會忽略非法字符;
所以我只要把請求的頁面數據解碼成“gbk”格式即可
修改後的代碼如下
response =requests.get(url).content.decode("gbk","ignore")
我們再來看看解碼後的打印結果
登登登登!是不是一切正常呢!嘻嘻嘻
我們已經成功獲取了頁面的數據
接下來就要定位到頁面裏的每一個章節的按鈕
首先我們按f12進入我們的開發者頁面
按照下圖操作
再點擊定位到這裏
於是我們就得知了這個元素在頁面中的位置
然後我們要用到一個叫做xpath的擴展工具,我用的是谷歌瀏覽器,xpath的安裝是需要導入的。
可參考:https://blog.csdn.net/yhnobody/article/details/81030436
安裝後以後,我們打開xpath
首先我們看控制檯
剛剛我們定位到第一章的按鈕位置是在
div標籤下的dl標籤下的dd標籤下面的a
所以對應我們在xpath上輸入//div/dl/dd/a
這裏解釋一下//是跨節點操作
然後在右邊看到我們的resuits,嘿嘿,成功得到我們想要的所有入口章節的信息
得到了這個位置信息後
接下來繼續敲代碼
首先導入etree包,因爲我們python是不能識別xpath的,所以要導包
注意這個包是自己要安裝的哦
# 從lxml中導入etree包
from lxml import etree
獲取HTML數據和通過xpath提取數據
# 獲取HTML數據
dom =etree.HTML(response)
# 通過xpath提取數據
html =dom.xpath("//div/dl/dd/a/")
我們把結果html打印一下
得到了這麼一大串的對象數據
但是現在的數據都擠在了一塊了,我們要把數據一 一取出來怎麼辦呢?
用到for 循環
for x in html:
print(x)
這個循環的意思就是,從html中把數據一 一提取到x裏面去
我們來看下打印結果
看!現在是不是我們的對象都乖乖的排好隊了呢
我們剛剛獲取的是對象數據,如果想進一步獲取網址
要再用一次xpath
還記得這個頁面嘛?
我們的小說的章節都在這個href裏面了
我們再用一次xpath獲取
# 獲取小說頁面網址
a=["url"] = x.xpath("./@href")[0]
打印下結果看看
歐耶,成功獲取了
emm…不過怎麼怪怪的,和我們平時看到的網址不太一樣啊
嗯,沒錯,少了前面的一段
我們來把他們拼接起來
a = url + x.xpath("./@href")[0]
打印一下
perfect!
然後我們要把這些數據裝進字典裏
# 創建一個新字典
dic = {}
# 獲取小說頁面網址
dic["url"] = url + x.xpath("./@href")[0]
接下來提取章節名也是同樣的方法,
./text()的作用是提取數據裏的文本數據
# 提取章節名
dic["name"] = x.xpath("./text()")[0]
看看成果
我們想要的數據已經一一對應起來啦
到這裏我們已經完成一大半啦
接下來要做的就是對章節網址進行請求
然後提取裏面的小說數據
我們來對章節的網址進行請求
並查看請求信息
response = requests.get(dic["url"]).content.decode("gbk", "ignore")
print(response)
成功獲得章節頁裏面的數據啦
那麼我們要怎樣才能把我們網頁裏面的小說文字提取出來呢
還是要用到我們的老朋友xpath
一樣的方法,先定位到小說文字元素,找到元素所在的位置
然後在我們的xpath上輸入//div[@class=‘zhangjieTXT’]
需要注意的一個就是別忘了 'zhangjieTXT’這裏是有個引號的,如果沒有了,就會定位不準確,導致得到很多我們不想要的數據哦…
這裏的操作和第一次時一樣的
doc = etree.HTML(response)
HTML = doc.xpath('//div[@class="zhangjieTXT"]/text()')
print(HTML)
到這裏就快要完成了
遍歷小說數據
for v in HTML:
print(v)
成功爬到了我們的小說文字
但是文字間的間隔太大了
不知道你看着爽不爽,反正我看着是很不爽
所以,安排!
先上圖
哈哈哈哈哈這樣的是不是舒服多了
怎麼實現呢
for v in HTML:
# 頭尾去空格
novel = v.strip()
strip()把頭尾的空格去掉就可以啦!
這裏給大家拓展一下:
去左邊的空格lstrip()
去右邊的空格rstrip()
接下來我們把爬到的數據保存到本地,就完成啦!
# 打開“小說”文件夾,將小說的章節名作爲保存的文件名,以“a”追加的方式,編碼成“utf-8”
f = open("小說/" + dic['name'] + ".txt", "a", encoding="utf-8")
# 寫入小說數據,\n是換行符
f.write(novel + "\n")
#關閉讀寫文件
f.close()
來看看運行的結果
大功告成!撒花完結!!!
最後附上源碼
import requests
from lxml import etree
# 章節菜單網址
url = "https://www.qqxs.cc/xs/116/116087/"
response = requests.get(url).content.decode("gbk", "ignore")
# 獲取頁面的HTML數據
dom = etree.HTML(response)
html = dom.xpath("//div/dl/dd/a")
for x in html:
# 創建一個新字典
dic = {}
# 獲取小說章節名
dic["name"] = x.xpath("./text()")[0]
# 提取小說章節url
dic["url"] = url + x.xpath("./@href")[0]
# print(dic)
# 對章節網址進行請求
response = requests.get(dic["url"]).content.decode("gbk", "ignore")
# print(response)
# 提取頁面中的HTML數據
doc = etree.HTML(response)
# 提取小說文字數據
HTML = doc.xpath('//div[@class="zhangjieTXT"]/text()')
# 遍歷小說數據
for v in HTML:
# 頭尾去空格
novel = v.strip()
# 打開“小說”文件夾,將小說的章節名作爲保存的文件名,以“a”追加的方式,編碼成“utf-8”
f = open("小說/" + dic['name'] + ".txt", "a", encoding="utf-8")
# 寫入小說數據,\n是換行符
f.write(novel + "\n")
#關閉讀寫文件
f.close()
Yhen有感
說實話,寫教程還真挺累的哈哈哈,也深切體會到之前大佬們寫教程的不易了。但當我寫完之後,我是真的滿滿的成就感,原來我也能自己寫這種博客,也能把我的知識和大家分享,雖然我懂的不多,但是我願意把我會的都和大家分享!
寫這個教程時,我也發現了很多問題,我自己嘗試解決問題時就是我在學習的一個過程。比如老師演示的時候,爬下來的數據是沒有空行的,但是我爬下來卻有很多空行,我就得想辦法解決,上網查到的消除空行的方法都是要寫入後再對txt文件進行處理,很麻煩。我把問題發到羣上後,有同學說可以用strip()去空行的方法,我試了一下,果然OK!感謝!
我在寫代碼時也和老師上課講的代碼作比較,想想老師用的方法我能否換個方法來實現同樣的效果呢,比如說網址拼接那裏我是直接拼接的…老師有沒有一些步驟是不必要的呢?有,比如老師上課時把字典裏的數據再裝進列表裏,然後再用for循環遍歷…我把結果打印出來,其實就是字典裏的數據,所以還何必多此一舉,裝進去再拿出來呢?而且後面完全是用不到這個列表裏的數據的。
很開心能在這裏給大家分享我的經驗
我還只是個小白,如果有什麼寫的不好,寫錯了的地方歡迎大家指正,有什麼問題都可以在評論區提出哦!我們一起共同進步!
希望大家能夠喜歡這篇文章,以後我也會繼續出其他的教程,把我的經驗分享給大家!謝謝
如果可以的話,可以點個贊鼓勵下小弟嘛?加個關注更好哦哈哈嘻嘻
我是Yhen,我們下次見