前段时间,因为暑假休假以及回来后忙于工作,所以CSDN博客一直未更新,大家是不是忘了我了。虽然工作忙,但是每天下班,还是会看一眼CSDN的APP,天天都有新粉丝的加入,我很欣慰,说明我在这个平台所作的努力没有白费,大家的支持就是我继续创作的动力。
这两天稍微空一点,我更新了下最新的爬取《我靠打爆学霸兑换黑科技》小说的爬取代码,这个小说不出意外的话,我会一直更新代码,至于爬取网站来自如下链接:
https://m.shuhaige.net/shu_243116.htmlhttps://m.shuhaige.net/shu_243116.html现在免费的小说网站越来越少,存在的时间也越来越短了,望大家且看且珍惜,至于这个网站的其他小说资源,我没有测试是否可用,有兴趣的朋友,请替换最后的倒数第三句代码的链接,测试下看看。
if __name__ == "__main__":main_url = "https://m.shuhaige.net/243116/"# 如需其他小说,请搜索网站后,替换这句里的链接看看start = 1 #选择章节数main(main_url,start)
另外提一句,如果你运行了我的代码,可能发觉很慢,因为我加了每爬取一章有3秒延迟,在代码开头的全局变量里设置,还是那句话,给这些免费的资源网站一点活路,这年头大家都不容易,我今天已完整爬取过一次这篇小说,我会把代码和小说上传到百度云盘方便大家下载,省的大家重复爬取,增加网站负担,同时有些朋友前面的章节已经看过了,所以我加了个可以选择章节的功能,如上代码所示,因为这个小说里有特殊的多余章节,所以可能章节数对不上,但是误差也就两章,最多就是往前多爬两章,大家可以忽略不记,按实际写入即可,如果你比较讲究,可以加上两章,比如现在最新的章节是1189+2=1191,把start = 1191,爬取的就是最后一章了,当然如果碰到爬取的章节,在特殊章节的前面就有可能有问题,大家按程序实际运行的显示章节计算即可。还有一个问题就是如果是选择跳过章节,可能程序开始运行时,需要等待一会,因为程序在爬取page页面,不是python死机,因为这个小说网站不是把所有的章节放一起,而是每页50个章节的链接页面,所以会有这个问题,等以后有机会,我会优化这个问题,另外这个网站好像还有随机的反爬策略,触发条件未知,也可能是人为监控,反正我的代码有从指定章节爬取的功能,不是什么大问题,只要设置好上面的start变量+2,保存代码后,重新运行程序,就能在原始文件上继续写入。
如果你不想学习爬虫代码,你可以不看以下内容,直接使用文末的代码。
我来说说代码的优化问题,首先,因为这个网站的构架比较特殊,如上所说它的各章节链接做成了50个章节一页,所以爬取的页面就比较多,所以我优化了requests和BeautifulSoup的调用,把重复的代码做成一个函数,减少代码量,如下:
def request_get(url,headers,soup_select,encode_mode="utf-8"):res = requests.get(url,headers = headers)res = res.content.decode(encode_mode)soup = bs(res,"html.parser")datas = []for each_soup_select in soup_select:datas.append(soup.select(each_soup_select))return datas
其中url是待爬取网页链接,headers网络请求头,soup_select是网页里BeautifulSoup需要读取爬取的标签头,因为我的程序中有一个函数getNextPageText中,需要连续查询两个不同的标签头,所以我在此函数中,设置了for循环来历遍所有的soup_select数组的元素,比如这样:["div.content p","div.pager a"],并放入BeautufulSoup的解析器中,提取出所需的元素内容。最后的encode_mode="utf-8"默认是"utf-8",代表这个网页的解码方式是"UTF-8",这个在调用函数时,可以自定义为其他,比如"GBK"等,请按你要爬取的网页源代码头自己分析,可以找到网页源代码中如下这样的地方查看:
<head><meta charset="UTF-8"></head>
其中的charset后的UTF-8就是解码方式。
此外,我还定义了一个清洗小说文本中的杂乱字符的函数,如这样,可以在replace_text数组中加入自己想去掉的文本,注意加入一个就要在这一行的字符串后加英文逗号。
def replaceTxt(text):replace_text = ['<p>','</p>','《我靠打爆学霸兑换黑科技》无错的章节将持续在书海阁小说网小说网更新,站内无任何广告,还请大家收藏和推荐书海阁小说网!','喜欢我靠打爆学霸兑换黑科技请大家收藏:(m.shuhaige.net)我靠打爆学霸兑换黑科技书海阁小说网更新速度全网最快。','本小章还未完,请点击下一页继续阅读后面精彩内容!','小主,这个章节后面还有哦,请点击下一页继续阅读,后面更精彩!','这章没有结束,请点击下一页继续阅读!']for rep in replace_text:text = text.replace(rep,"")return text
因为有些章节有多页(通常是两页),如下图所示:
正常无分页的章节,如下:
而有些章节只显示一页 ,先分析下网页源码,如下:
根据上面分析,所以我编写了一个自迭代函数来处理这种情况,每句代码我都写了注释,如下:
def getNextPageText(next_page_tag,headers,name,page_count):page = next_page_tag[1]# 这里是初次调用或上一次迭代调用本函数的前的request_get返回的datas[1],也就是解析"div.pager a"标签的结果,其中有判断是否有如上图的"下一页"或"下一章"nextpage_tag = page[2]# 这个就是data[1]中解析"div.pager a"标签的返回结果,也就是a标签数组中的第三个,这个元素可能是"下一页"或"下一章"if nextpage_tag.text == "下一页":# 单独处理下一页的情况time.sleep(delay_time-1)# 延时page_count += 1# 给每章的页数计数,并返回,方便之后在信息中输出url = "https://m.shuhaige.net" + nextpage_tag['href']# 取出a标签中的href下一页或下一章链接datas = request_get(url,headers,["div.content p","div.pager a"]) #解析新的分页中的小说内容和下一页/章元素标签nextpage_text,page_count = getNextPageText(datas,headers,name,page_count)#重复迭代调用此函数,判断是否还有新的分页,比如第三页text = "\n".join(map(str,datas[0])) #合并读取到的小说<P>元素内容text = text + nextpage_text #把迭代获取到的新分页内容合并到老分页中return text,page_count#返回所有分页的小说文本和分页数 return "",page_count#如果没有新的分页或只有下一章,就直接返回空字符
最后,在getText函数中,我没有像以前一样,循环拼接request返回的datas,而是使用了如下代码:
text = name + "\n" + "\n".join(map(str,datas[0])) + nextpage_text# nextpage_text处理了一个章节中有多页的情况
这样调用应该更高效,顺便一提,datas是一个tag类型数组,所以要转换成str,需要调用map函数,最后用join链接每行小说文本,并在每行加入一个"\n"软回车。
基本的代码解释到这里,有问题的小伙伴如果有什么不懂,可以私信或者评论区联系我,看到后会回复。
最后放上全部代码和最新小说链接:
import requests
from bs4 import BeautifulSoup as bs
import timedelay_time = 3# 延时3秒,防止被和谐,请各位手下留情,人家开网站也不容易,现在能找到一个免费站点不容易
file_name = "11.小说爬取\书海阁\我靠打爆学霸兑换黑科技_20240828.txt"
count = 0def request_get(url,headers,soup_select,encode_mode="utf-8"):res = requests.get(url,headers = headers)res = res.content.decode(encode_mode)soup = bs(res,"html.parser")datas = []for each_soup_select in soup_select:datas.append(soup.select(each_soup_select))return datasdef replaceTxt(text):replace_text = ['<p>','</p>','《我靠打爆学霸兑换黑科技》无错的章节将持续在书海阁小说网小说网更新,站内无任何广告,还请大家收藏和推荐书海阁小说网!','喜欢我靠打爆学霸兑换黑科技请大家收藏:(m.shuhaige.net)我靠打爆学霸兑换黑科技书海阁小说网更新速度全网最快。','本小章还未完,请点击下一页继续阅读后面精彩内容!','小主,这个章节后面还有哦,请点击下一页继续阅读,后面更精彩!','这章没有结束,请点击下一页继续阅读!']for rep in replace_text:text = text.replace(rep,"")return textdef getPage(main_url,start):headers = {'accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7','referer':'https://m.shuhaige.net/shu_243116.html','user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0'}page_urls = request_get(main_url,headers,["span.pagenum select option"])page_urls = page_urls[0]sum_text_size = 0for page_url in page_urls:p_url = "https://m.shuhaige.net" + page_url['value']sum_text_size = sum_text_size + getUrl(p_url,headers,start)return sum_text_sizedef getUrl(page_url,headers,start):urls = request_get(page_url,headers,["ul.read li a"])urls = urls[0]sum_page_size = 0for url in urls:global countcount += 1 if count >= start:time.sleep(delay_time) #手工延时,防止被和谐name = url.textul = "https://m.shuhaige.net" + url['href']start_time = time.time()text_size,page_count = getText(name,ul)if page_count > 1:page_txt = f"共{page_count}页,"else:page_txt = ""print(name,f"已下载完成!(耗时:{time.time() - start_time}秒,{page_txt}字数:{text_size})")else:text_size = 0sum_page_size += text_sizereturn sum_page_sizedef getNextPageText(next_page_tag,headers,name,page_count):page = next_page_tag[1]nextpage_tag = page[2]if nextpage_tag.text == "下一页":time.sleep(delay_time-1)page_count += 1url = "https://m.shuhaige.net" + nextpage_tag['href']datas = request_get(url,headers,["div.content p","div.pager a"]) nextpage_text,page_count = getNextPageText(datas,headers,name,page_count)text = "\n".join(map(str,datas[0])) text = text + nextpage_textreturn text,page_countreturn "",page_countdef getText(name,url):headers = {'accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7','referer':'https://m.shuhaige.net/shu_243116.html','user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0' }datas = request_get(url,headers,["div.content p","div.pager a"])page_count = 1nextpage_text,page_count = getNextPageText(datas,headers,name,page_count)text = name + "\n" + "\n".join(map(str,datas[0])) + nextpage_texttext = replaceTxt(text)with open(file_name,"a+",encoding="utf8") as f:f.write(text + "\n")return len(text),page_countdef main(main_url,start=1):start_time = time.time()sum_text_size = getPage(main_url,start)runtime = (time.time()-start_time) / 60print(f"已全部下载!(共耗时:{runtime:.2f}分钟,总字数:{sum_text_size})")if __name__ == "__main__":main_url = "https://m.shuhaige.net/243116/"# 如需其他小说,请搜索网站后,替换这句里的链接看看start = 1 #选择章节数main(main_url,start)
小说和代码文件链接如下:
通过百度网盘分享的文件:书海阁
链接:https://pan.baidu.com/s/1kClUGhI1ZBQTN--IkrwznQ?pwd=8888
提取码:8888
--来自百度网盘超级会员V8的分享
谢谢观看,再见!