點贊再看,養成習慣。微信公衆號搜索「Job Yan」關注這個愛發技術乾貨的 Coder。本文 GitHub https://github.com/JobYan/PythonPearls 已收錄,還有算法學習、爬蟲進階等資料,以及個人系列文章,歡迎 Star 和完善。html
你們好,我是 「Job」。本篇文章是「保姆級」帶你入門和進階網絡爬蟲系列文章的開篇,在本篇文章中我會手把手教你:如何利用簡單的方法騙過百度文庫的反爬機制,爬取指定的文檔頁面,並將文檔下載下來 skr~。舒適提示,本文字數較多,可能須要閱讀較長時間,建議先點贊收藏,防止迷路。python
想必你們都對百度文庫已經很熟悉了,百度文庫如今的收費策略,簡直不要太霸道。百度文庫的 VIP 策略有點噁心,以前積分能夠換取下載券,爲了得到積分,我當時還好心的把本身的一些文檔上傳到了百度文庫。而如今積分根本用不到了,全是 VIP。最噁心的是,我以前上傳的文檔明明設置的是積分下載,而百度直接設置成爲 VIP 專享,因此百度在利用咱們的文檔斂財,而給咱們的積分卻不能下載任何文檔,我能說這是平臺的壟斷行爲嗎?這樣好嗎?這樣很差,但願他耗子尾汁。這讓我想起了之前網上流傳的一張 Gif。git
可能不少人和個人感受是同樣的,做爲平臺不能只關心本身的利益,還要考慮用戶和貢獻者的利益。因此,本期我們學習如何利用 Python 編寫爬蟲腳本,爬取某些百度文庫的文檔,找回一些文庫用戶的存在感。github
說了這麼多無關的內容,接下來我們開始正式的教學內容。爲了便於講解,我把抓取的過程分紅了 4 步,以下圖所示:算法
須要注意的事項有兩點:
第一點,咱們爬取到的文件和文庫中的原文件是有區別的,以PPT類型的文件爲例,咱們在文檔頁面看到的內容實際上是 PPT 通過渲染後的圖片。也就是說瀏覽器中咱們看到的都是一些圖片。因此咱們能夠利用 Python 等編寫爬蟲腳本,爬取網頁中的相關圖片。再將這些圖片合併成 PDF 文檔。
第二點,不一樣文件類型的爬取方式是不一樣的,這裏我先賣個關子。下一篇博文教你下載 Word,TXT,PPT 等類型的文檔。瀏覽器
下面以某篇 PPT 文檔爲例,分步驟展開講解。微信
首先在瀏覽器中訪問文庫首頁並獲取某 PPT文檔 的連接。我打開文庫首頁以後,隨便找了篇 PPT 文檔。在這裏以及後面的示例程序中,我就不粘貼文檔的真實連接了,一概以https://wenku.baidu.com/view/xxx.html
來代替。網頁截圖以下:cookie
獲取文檔網頁連接之後,咱們即可以利用 Python 自帶的 requests 庫獲取網頁內容的獲取。網頁的代碼以下:網絡
import requests url = "https://wenku.baidu.com/view/xxx.html" header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'} res = requests.get(url, headers=header) # Get 網頁內容
我猜這個時候,不少小夥伴已經躍躍欲試了,很快就抄起鍵盤使出了一套 Ctrl+C
和 Ctrl+V
的組合拳,趁 IDE 沒有防備,很快啊,反手就是一個 F5
。此時,一絲不易覺察的笑容從你的臉上掠過,然而年輕人你笑得太早了,很快啊,你就露出驚訝的神情,「Job」老師,發生什麼事了?原來啊,就在前些日子,百度文庫修改了反爬策略,之前能夠很容易獲取到的網頁內容,如今沒法正常獲取了。函數
從下圖中咱們能夠看出,使用上述代碼下載到的 html 內容和本來的 html 內容是不同的。左邊紅框中的內容利用上面的代碼抓取到的 html 內容,右側紅框中的內容是 Firefox 瀏覽器保存的離線網頁內容。二者是不一致的,而且左側的內容中黃色框標識的地方好像表示文庫團隊在收集數據從而達到更好的反爬效果。[舒適提示:點擊圖片即可查看高清大圖]
而在上面的代碼正是經過以前簡單的方式進行爬取,因此出現了問題。不過不要慌,接下來,我會教會你如何去解決這個問題。接下來,我們欣賞一副優美的圖片,讓心靈的窗戶休息一下。
相信看到這裏的小夥伴都是很想知道問題答案的,我也就不賣關子了,直接放大招(貼代碼)。下面的代碼是我通過了一下午的調試和觀察得出來的解決問題的方法。
import requests url = "https://wenku.baidu.com/view/xxx.html" header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'} res = requests.get('https://wenku.baidu.com') cookie = res.cookies # Get 網頁內容 res = requests.get(url, headers=header, cookies=cookie)
在說出問題解決方法以前,請你們認真閱讀上面的代碼,並找出和以前代碼的不一樣之處。
上面的代碼很簡單,相信細心的小夥伴已經很輕鬆就發現了和以前代碼的不一樣之處,那就是在抓取目標網頁以前,先抓取了一條和百度相關的網頁,在這裏我們先抓取的是百度文庫的首頁,即 https://www.wenku.baidu.com
,而後利用此次的 cookies 信息,對文庫的指定網頁進行抓取。
其實簡單理解就是:首先讓百度文庫認爲我們是有身份的,這裏的身份就是我們訪問百度文庫首頁得到的 cookies,而後憑藉該身份就能夠抓取百度文庫的指定網頁。趁其還沒有覺察之際,我們趕忙把指定網頁爬取下來,「來騙來偷襲」。從目前來看這種簡單的技巧能夠頗有效的解決被百度反爬的問題。
經過上述操做以後,咱們獲取到了和瀏覽器中相同的網頁內容。左邊紅框中的內容利用上面的代碼抓取到的 html 內容,右側紅框中的內容是 Firefox 瀏覽器保存的離線網頁內容。二者是不一致的,不過不要緊,咱們已經抓取到了咱們想要的內容。
這部分是本文的關鍵。由前面的內容咱們知道了,PPT 以圖片的形式存在於網頁中。那麼很簡單,咱們首先能夠利用瀏覽器的網頁調試功能來分析網頁中的各個元素。能夠看到網頁上的 HTML 元素的嵌套就跟洋蔥似的。一層嵌套着一層,而咱們獲取的圖片的連接是洋蔥裏的最裏層,因此咱們要一層一層的撥開它的心
,從而獲取圖片的資源連接。下圖展現了剝洋蔥的過程,很生動形象。經過這種方法,咱們能夠很輕鬆的找到 PPT 頁面的連接。
在找到第一頁的 PPT 圖片以後,其他圖片很能夠很容易的被找到,以下圖綠框中標註的內容。經過這種方式咱們能夠很方便的找到各頁圖片的連接,但要程序去作,那應該怎樣去編寫代碼呢?別慌,其實咱們找到圖片的連接以後,接下來編寫代碼的工做就簡單了,'人生苦短,我用 Python',Python 中有許多現成的庫函數能夠幫助咱們完成這個簡單的任務,接下來咱們會利用BeautifulSoup
來查找圖片的連接。
爲方便你們的理解,我先把代碼放到下方,請你們先閱讀一遍,接下來我會對關鍵地方進行講解。
import html from bs4 import BeautifulSoup html_content = res.text # 網頁文本內容 # 接下來,利用 Beautiful 找尋 res.text 中的相關字段 soup = BeautifulSoup(html_content, 'html.parser') title = soup.title.text title = title.replace(' - 百度文庫', '') print('文章標題:' + title) # 利用 BeautifulSoup 獲取文檔圖片的連接 img_srcs = soup.find_all('img') img_num = len(img_srcs) print(f"該 PPT 文檔總共包含 {img_num} 張圖片。")
在第 6 行,使用 BeautifulSoup 解析網頁內容,可以獲得一個 BeautifulSoup
的對象。(更多 BeautifulSoup 的內容,請查閱官方的幫助文檔,放心該文檔提供了中文版的)。接下來,就能夠很方便的獲取網頁內容中標籤的相關信息。以下圖所示,圖片的連接包含於 標籤中,因此咱們利用
img_srcs = soup.find_all('img')
能夠很輕鬆的獲取該網頁中包含的所有 標籤。
可能有小夥伴會問, 標籤中會不會包含着其餘非 PPT 圖片的連接?頗有可能,但我如今並未發現這種狀況,因此你們能夠按照這種方式來獲取圖片的連接。
接下來的工做就很簡單了,先上代碼後解釋,關鍵內容已寫註釋。
# 定義下載圖片的函數,方便後續下載圖片 def download_img(img_url, img_name, header, cookie): try: r = requests.get(img_url, headers=header, stream=True, cookies=cookie) if r.status_code == 200 or r.status_code == 206: open(img_name, 'wb').write(r.content) # 將內容寫入圖片 return True, None except Exception as e: return False, traceback.format_exc() i = 0 # 遍歷獲取到的標籤列表 for img_src in img_srcs: i = i + 1 print(f"正在下載第 {i} 張圖片,進度 {i} / {img_num} 。") # <img src="https://wkretype.bdimg.com/retype/zoom/xxx" alt=""> img_herf = img_src.get('src') # 獲取圖像連接 if img_herf == None: # 有的圖片用的是'data-src' # 即:<img data-src="https://wkretype.bdimg.com/retype/zoom/xxx" alt=""> img_herf = img_src.get('data-src') # 獲取圖像連接 try: img_herf = html.unescape(img_herf) except: print(f"第 {i} 張圖片下載失敗。") continue img_name = str(i) + '.png' # 下載圖片 ret_val, message = download_img(img_herf, img_name, header, cookie) if ret_val: print(f"第 {i} 張圖片下載成功 。") else: print(f"第 {i} 張圖片下載失敗,錯誤信息以下:\n", message)
下面的工做也很簡單,將下載到的圖片輸出到 PDF 文件中。先上代碼,後解釋。
import fitz doc = fitz.open() img_dir, _ = os.path.split(img_paths[0]) for img_path in img_paths: imgdoc = fitz.open(img_path) # 打開圖片 pdfbytes = imgdoc.convertToPDF() # 使用圖片建立單頁的 PDF imgpdf = fitz.open("pdf", pdfbytes) doc.insertPDF(imgpdf) # 將當前頁插入文檔 # 保存在圖片文件夾下 save_pdf_path = os.path.join(img_dir, pdf_name) if os.path.exists(save_pdf_path): os.remove(save_pdf_path) doc.save(save_pdf_path) # 保存pdf文件 doc.close()
在上面的代碼中,咱們藉助 fitz 庫的幫助,完成了將圖片直接輸出爲 PDF 文件的工做。
總結:
在本篇文章中,咱們學習瞭如何避開百度的反爬機制,得到 PPT 的網頁內容,並利用 BeautifulSoup 對網頁內容進行解析,獲取圖片連接地址,接着,咱們經過連接地址下載圖片,最後,咱們把圖片合併保存爲 PDF 文檔的形式。
若是個人文章幫到了你,請給一個當心心,有了你的鼓勵我後續會更有動力創做出更加優質的文章,從而幫助到更多的小夥伴。固然,若是你以爲本文章在某些方面是不夠好的,請在評論區留言,你的意見對我真的很是重要,謝謝。
我已經將本文章中講述的源碼都打包好了,而且還利用 pyinstaller 生成了可執行文件,若是你有這方面需求的話,請關注公衆號「Job Yan」,後臺回覆百度文庫,便可獲取相關文件,後期程序更新的話,我會第一時間將相應文件更新到微信公衆號後臺。本系列教程持續更新,若是你也對爬蟲感興趣,歡迎關注,我們共同進步,一塊兒成長。
歡迎各位小夥伴用大家心愛的大手機掃描屏幕上的二維碼(長按二維碼能夠識別或者保存到本地喲😘)。這是個套了支付寶馬甲的公衆號二維碼,不信你就掃掃看(手動斜眼)。
文章持續更新,能夠微信公衆號搜索「Job Yab」第一時間閱讀,本文 GitHub https://github.com/JobYan/PythonPearls 已經收錄,還有算法學習、爬蟲進階等資料,歡迎 Star 和完善。