朋友爬了本小說讓我看看,評價一番,“操蛋,你從哪裏學的?這就是一坨屎的爬蟲·······”
至於我爲什麼發這麼火,原因如下:
- 朋友的小說全部放在文件夾中,就是一章一個text文本, 沒有目錄的存在,而且目錄章節混亂,我大致看了下,第五章就跳到第七章了, 中間的不知道怎麼沒了。
- 打開小說一看, 密密麻麻擠着一起,沒有一點段落感,而且還有一些html代碼,沒有處理乾淨,最重要的,居然還有一大批網址在裏面,簡直就是不走心
- 第三,爬取的小說根本就不能算一整本,我看了一下文件數量,足足少了二十多章,我評價到看個鬼,你自己看看能不能行 !
- 朋友看完,自己也很無語,至於他爲什麼會出現這種情況,我想很多爬蟲新手們,都會出現這樣的情況,而且這些問題都是出自細節中,新手們,不怎麼會考慮周到,那麼既然朋友也出現了這樣的問題,他讓我幫他改改,於是改完之後,我寫下這篇博客,讓更多人真正的爬小說,而不是爬一坨屎,自己都看不下去的那種坨屎!!!!
看了一下朋友的代碼,發現問題的所在之處,都是細節問題!
爬蟲不注意細節,你談什麼爬蟲!
解決方案如下:
這一期還是做一個乾貨分享,都是我半年以來的爬蟲經驗,需要教學可以私聊我,在校學生還是需要一點經濟支持的!
如何產生章節:
自己問自己,有多少人爬取小說是這樣的,你自己能看嗎?
寫代碼的時候大部分人是這樣的
with open('**.text', 'w') as fw:
fw.write(r.text)
關於文件的寫入, ‘w’ 的方式 是覆蓋寫, 沒有就創建, 那麼我們寫小說就不需要用這個, 使用
‘a’ 追加寫的模式, 然後添加適當的分隔符, 只有文本中添加目錄, 整個txt在手機中才會顯示出目錄的存在 ,我的實例如下: 最好加點文字提示, 代表這章節下載成功到總txt中 !
path = 'D://爬取小說//'
os.chdir(path) # 進入這個文件夾
with open('酒神.txt', 'a+', encoding='utf-8') as fw:
fw.write(''.join(items['title']) + '\n\n\n' + '- ' * 40)
fw.write(''.join(items['text']))
print(f'{items["title"]} 下載完成!')
如何章節順序穩定:
一般我們都是從目錄url 中, 去獲取我們需要的章節網址, 這裏拿我爬取的網址實例:
這裏我們就能獲取所有章節的網址了, 只要進行適當的拼接處理, 那麼很多人就舒服了,直接獲取整個url列表, 直接返回給調用函數, 舒服吧? 你電腦不舒服, 關於return 和 yield 你真的懂嗎? 如果你請求的網址很多, 一定時間請求次數過多,就容易丟失網址,我想大部分人都是返回列表,然後遍歷列表吧? 萬一丟了一個章節網址呢? 是不是就會出現章節混亂的情況,使用yield 就不需要考慮這麼多因素了, 它可以直接調用一次返回一次,有效的避免了可能的因素, 我覺得很好用, 我也推薦使用, 不是所有的返回都是用return!!!
示例如下:
page_url = html.xpath('//div[@id="list"]/dl/dd/a/@href')
for url in page_url[222:]:
url = f'http://www.biquge.info/11_11079/{url}'
yield url
如何保證文字的處理:
爬取小說這樣的文字量很多的情況下, 文字的處理顯得極爲重要了,爬取小說不推薦使用正則re,也不推薦使用soup, 原因你獲取不了網頁自帶的換行符和縮進符, 比如 \xboo 之類的, 如果你獲取不了文本自帶的這些,那麼你就得自己添加,可以使用re的sub進行適當的替換換行,這就很麻煩,這裏一定推薦使用xpath的text() 去匹配, 方便快捷,爬小說的小助手!
示例如下:
text = html.xpath('//div[@id="content"]/text()')
非常的簡單, 而且xpath的匹配非常的快,不會的朋友一定要學,soup真的不推薦,大工程起來真的慢!
如何應對ip限制等因素:
他在爬小說的時候,也出現了這樣的問題,在一個urls列表中, 竟然有的能請求成功, 有的不能請求成功, 明明都是網址沒有錯, 我也能打得開,但就是出現了這樣的bug,很鬧騰,但是後面我還是修復了。
bug 出現 : 所有的網址 一定是正確的, 我可以確保。
爲什麼會出現這樣的情況,高頻發的請求網址,如果不是使用框架, 那麼就需要設置延遲時間了。比如sleep() 或者 request 加入參數 timeout ,不然很容易被網址通過請求次數 進而識別出來 這是一個爬蟲程序, 也就是非人類操作, 那麼他就可以不讓你請求,從而你就爬蟲失敗!
這樣搞:
多次請求,模塊分離,你搞我, 我也可以搞你!
將獲取文本的函數 分離出來, 在parse_page 進行三次判斷,失敗就回溯,三次回溯,實測,請求被擋住的概率大幅降低。這是一個不錯的方法, 當然, 還需要加入 sleep(), 來控制代碼的延遲時間。
def parse_page_error(self, r):
# 爲處理異常:
r.encoding = r.apparent_encoding
html = etree.HTML(r.text)
title = html.xpath('//div[@class="bookname"]/h1/text()')
text = html.xpath('//div[@id="content"]/text()')
items = {}
items['title'] = title
items['text'] = text
self.save_text(items)
def parse_page(self):
"""
分析每一章節 然後下載, 次數過快 容易炸ip 三次保底請求 !
"""
for url in self.get_page():
r = requests.get(url, headers=self.headers)
time.sleep(0.7)
if r.status_code == 200:
self.parse_page_error(r)
else:
print(f'該 {url}未下載成功! 再次請求')
rr = requests.get(url, headers=self.headers)
if rr.status_code == 200:
self.parse_page_error(rr)
else:
print("第三次請求!")
rrr = requests.get(url, headers=self.headers)
self.parse_page_error(rrr)
print('全部下載完成!')
這一期乾貨就到此爲此, 主要還是滿足自己的需求,2020年了,看小說還不會爬蟲,你有多撈!
爬蟲全程序:
# -*- coding : utf-8 -*-
# @Time : 2020/6/2 16:13
# @author : 沙漏在下雨
# @Software : PyCharm
# @CSDN : https://me.csdn.net/qq_45906219
import requests
from lxml import etree
import os
import time
class Spider:
def __init__(self):
self.start_url = 'http://www.biquge.info/11_11079/'
self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/81.0.4044.129 Safari/537.36',
'Host': 'www.biquge.info',
'Referer': 'http://www.biquge.info/11_11079/5216668.html',
'Cookie': 'clickbids=11079; Hm_lvt_6dfe3c8f195b43b8e667a2a2e5936122=1591085546;'
' Hm_lvt_c979821d0eeb958aa7201d31a6991f34=1591085539,1591085553,1591085815; '
'Hm_lpvt_6dfe3c8f195b43b8e667a2a2e5936122=1591087376; '
'Hm_lpvt_c979821d0eeb958aa7201d31a6991f34=1591087377'}
def get_page(self):
"""
獲得每一章節的網址
yield 回去
"""
r = requests.get(self.start_url, headers=self.headers)
if r.status_code == 200:
r.encoding = r.apparent_encoding
html = etree.HTML(r.text)
page_url = html.xpath('//div[@id="list"]/dl/dd/a/@href')
for url in page_url[222:]:
url = f'http://www.biquge.info/11_11079/{url}'
yield url
def save_text(self, items):
"""
根據章節下載'
"""
path = 'D://爬取小說//'
os.chdir(path) # 進入這個文件夾
with open('酒神.txt', 'a+', encoding='utf-8') as fw:
fw.write(''.join(items['title']) + '\n\n\n' + '- ' * 40)
fw.write(''.join(items['text']))
print(f'{items["title"]} 下載完成!')
def parse_page_error(self, r):
# 爲處理異常:
r.encoding = r.apparent_encoding
html = etree.HTML(r.text)
title = html.xpath('//div[@class="bookname"]/h1/text()')
text = html.xpath('//div[@id="content"]/text()')
items = {}
items['title'] = title
items['text'] = text
self.save_text(items)
def parse_page(self):
"""
分析每一章節 然後下載, 次數過快 容易炸ip 三次保底請求 !
"""
for url in self.get_page():
r = requests.get(url, headers=self.headers)
time.sleep(0.7)
if r.status_code == 200:
self.parse_page_error(r)
else:
print(f'該 {url}未下載成功! 再次請求')
rr = requests.get(url, headers=self.headers)
if rr.status_code == 200:
self.parse_page_error(rr)
else:
print("第三次請求!")
rrr = requests.get(url, headers=self.headers)
self.parse_page_error(rrr)
print('全部下載完成!')
jiushen = Spider()
jiushen.parse_page()