爬虫实战(六):爬笔趣阁
一、 网站分析
1、 页面分析
通过抓包分析可以得到,该网站为静态网站,所有信息都保存在页面源码中,可以直接从页面源码获取信息。
在目录中,发现其全部存储在一个dl的标签中
在搜索目录中,搜索内容存储在一个列表中,我们可以通过获取列表的长度来知道是否查找到了结果;如果没有搜索到结果,则不会将列表哦渲染出来,我们可以通过<div class="novelslistss"></div>
来判断是否查找成功
2、 源码分析
通过分析源码,发现,目录包裹在<dl></dl>
,内容包裹在一个<div id="content"></div>
中
3、 链接分析
# 通过几次搜索可以得到几个url
# https://www.bqg.org/modules/article/search.php?searchkey=%BE%F8%CA%C0%CE%E4%C9%F1 # 绝世武神
# https://www.bqg.org/modules/article/search.php?searchkey=%BE%F8%CA%C0%CC%C6%C3%C5 # 绝世唐门
url = "https://www.bqg.org/modules/article/search.php?searchkey=%s"
from urllib import parse
print(parse.quote("绝世武神".encode("gbk")))
# 在多次尝试下,发现,其先是对文本内容进行gbk编码,再进行url编码
# 故,我们可以模拟搜索工具,来对内容进行精确的查找
name = input("请输入书名:") # 获取用户输入的书名
print(url % parse.quote(name.encode("gbk"))) # 得到url
二、 编写代码
1、 获取目录
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "biquge.py"
__time__ = "2022/7/6 14:03"
# 导入必要的模块
import requests, re # 发送请求,使用正则获取全部内容
from urllib import parse # 进行书名的编码
from fake_useragent import UserAgent # UA伪装
# 这次获取的是风起龙城的目录
url = "https://www.bqg.org/53_53985/" # 要爬取的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.9',
'Accept-Encoding': ' gzip, deflate, br',
'Accept-Language': ' zh-CN,zh;q=0.9',
'Cache-Control': ' no-cache',
'Connection': ' keep-alive',
'Cookie': ' jieqiVisitId=article_articleviews%3D53982; jieqiVisitTime=jieqiArticlesearchTime%3D1657088500; clickbids=53982',
'Host': ' www.bqg.org',
'Pragma': ' no-cache',
'Referer': ' https://www.bqg.org/',
'sec-ch-ua': ' " Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"',
'sec-ch-ua-mobile': ' ?0',
'sec-ch-ua-platform': ' "Windows"',
'Sec-Fetch-Dest': ' document',
'Sec-Fetch-Mode': ' navigate',
'Sec-Fetch-Site': ' same-origin',
'Sec-Fetch-User': ' ?1',
'Upgrade-Insecure-Requests': ' 1',
'user-agent': UserAgent().random
}
def get_menu(url):
headers.update({'user-agent': UserAgent().random}) # 随机请求头
resp = requests.get(url, headers) # 发起请求
resp.encoding = resp.apparent_encoding # 要文件的编码应该为gbk
temp = re.search("正文.*?</dl>", resp.text).group() # 进行剪切,去除开头那新更新的目录
lis = re.findall(r'<a href="(.*?)">(.*?)</a>', temp) # 使用正则获取到目录和对应目录的链接
url_de = []
chapters = []
for i in lis:
url_de.append(f"{url}{i[0]}")
chapters.append(i[1])
# print(url_de, chapters)
return url_de, chapters # 返回结果
get_menu(url)
2、 访问目录
def get_content(url):
headers.update({'user-agent': UserAgent().random}) # 随机请求头
resp = requests.get(url, headers) # 获取响应
resp.encoding = resp.apparent_encoding # 编码
content = re.search('<div id="content" name="content">(?P<content>.*?)</div>', resp.text, re.S).group("content") # 获取到内容
content = re.sub(r'<br.*?>', "\n", content) # 使用正则替换清洗数据
content = re.sub(r' ', " ", content) # 使用正则替换清洗数据
return content # 返回结果
get_content("https://www.bqg.org/53_53985/38645272.html") # 测试使用
3、 下载数据
def save_data(url_):
with open("./风起龙城.txt", "w", encoding="utf-8") as f:
urls, menus = get_menu(url_)
for index, url in enumerate(urls):
f.write(f"==============={menus[index]}===============\n")
print(f"正在下载:{menus[index]}")
content = get_content(url)
f.write(content + "\n")
print(f"{menus[index]},下载完成")
save_data("https://www.bqg.org/53_53985/")
4、 搜索功能
url = "https://www.bqg.org/modules/article/search.php?searchkey=%s"
from lxml import etree
from prettytable import PrettyTable
def have_content(text):
# 当查找到内容时,展示查找到的内容给用户选择
html = etree.HTML(text)
li_s = html.xpath("//*[@id='main']/div[1]/li")
table = PrettyTable(['序号',"类型", '书名','作者'])
lis_ = []
index = 0
for index, li in enumerate(li_s):
type_ = li.xpath("./span[@class='s1']/text()")
name = li.xpath("./span[@class='s2']/a/text()")
url = li.xpath("./span[@class='s2']/a/@href")
lis_.append(url)
author = li.xpath("./span[@class='s4']/text()")
table.add_row([index + 1,type_, name, table])
print(table)
i = input("请输入要下载的序号:")
if i < index and i > 0:
return lis_[i - 1]
print("请按要求输入哦!")
def search(n):
arg = parse.quote(n.encode("gbk"))
headers.update({'user-agent': UserAgent().random}) # 随机请求头
resp = requests.get(url % arg, headers) # 发起请求
resp.encoding = resp.apparent_encoding # 设置当前编码
tet = resp.text # 获取内容
if re.search("错误原因:对不起,没有搜索.*?文章!", tet):
print("对不起,没有搜索到您要的文章!")
return
if re.search("错误原因:对不起,两次搜索.*?秒", tet):
print("对不起,两次搜索的间隔时间不得少于30秒")
return
# 剩下的都是查到内容的
have_content(tet) # 获取具体的下载名
name = input("请输入要下载的小说:")
search(name)
三、 总代码
# !/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "biquge.py"
__time__ = "2022/7/6 14:03"
# 导入必要的模块
import requests, re, sys # 发送请求,使用正则获取全部内容
from urllib import parse # 进行书名的编码
from fake_useragent import UserAgent # UA伪装
url = "https://www.bqg.org/modules/article/search.php?searchkey=%s" # 查找的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.9',
'Accept-Encoding': ' gzip, deflate, br',
'Accept-Language': ' zh-CN,zh;q=0.9',
'Cache-Control': ' no-cache',
'Connection': ' keep-alive',
'Cookie': ' jieqiVisitId=article_articleviews%3D53982; jieqiVisitTime=jieqiArticlesearchTime%3D1657088500; clickbids=53982',
'Host': ' www.bqg.org',
'Pragma': ' no-cache',
'Referer': ' https://www.bqg.org/',
'sec-ch-ua': ' " Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"',
'sec-ch-ua-mobile': ' ?0',
'sec-ch-ua-platform': ' "Windows"',
'Sec-Fetch-Dest': ' document',
'Sec-Fetch-Mode': ' navigate',
'Sec-Fetch-Site': ' same-origin',
'Sec-Fetch-User': ' ?1',
'Upgrade-Insecure-Requests': ' 1',
'user-agent': UserAgent().random
}
def have_content(text):
# 当查找到内容时,展示查找到的内容给用户选择
html = etree.HTML(text)
li_s = html.xpath("//*[@id='main']/div[1]/li")
table = PrettyTable(['序号',"类型", '书名','作者'])
lis_ = []
index = 0
for index, li in enumerate(li_s):
type_ = li.xpath("./span[@class='s1']/text()")[0]
name = li.xpath("./span[@class='s2']/a/text()")[0]
url = li.xpath("./span[@class='s2']/a/@href")[0]
lis_.append(url)
author = li.xpath("./span[@class='s4']/text()")[0]
table.add_row([index + 1,type_, name, table])
print(table)
i = input("请输入要下载的序号:")
if i <= index and i > 0:
return lis_[i - 1]
print("请按要求输入哦!")
sys.exit(0)
def search(n):
arg = parse.quote(n.encode("gbk"))
headers.update({'user-agent': UserAgent().random}) # 随机请求头
resp = requests.get(url % arg, headers) # 发起请求
resp.encoding = resp.apparent_encoding # 设置当前编码
tet = resp.text # 获取内容
if re.search("错误原因:对不起,没有搜索.*?文章!", tet):
print("对不起,没有搜索到您要的文章!")
return
if re.search("错误原因:对不起,两次搜索.*?秒", tet):
print("对不起,两次搜索的间隔时间不得少于30秒")
return
# 剩下的都是查到内容的
return have_content(tet) # 获取具体的下载名,并且把url返回
def get_menu(url):
headers.update({'user-agent': UserAgent().random}) # 随机请求头
resp = requests.get(url, headers) # 发起请求
resp.encoding = resp.apparent_encoding # 要文件的编码应该为gbk
temp = re.search("正文.*?</dl>", resp.text).group() # 进行剪切,去除开头那新更新的目录
lis = re.findall(r'<a href="(.*?)">(.*?)</a>', temp) # 使用正则获取到目录和对应目录的链接
url_de = []
chapters = []
for i in lis:
url_de.append(f"{url}{i[0]}")
chapters.append(i[1])
# print(url_de, chapters)
return url_de, chapters # 返回结果
def get_content(url):
headers.update({'user-agent': UserAgent().random}) # 随机请求头
resp = requests.get(url, headers) # 获取响应
resp.encoding = resp.apparent_encoding # 编码
content = re.search('<div id="content" name="content">(?P<content>.*?)</div>', resp.text, re.S).group("content") # 获取到内容
content = re.sub(r'<br.*?>', "\n", content) # 使用正则替换清洗数据
content = re.sub(r' ', " ", content) # 使用正则替换清洗数据
return content # 返回结果
def save_data(url_, name):
with open(f"./{name}.txt", "w", encoding="utf-8") as f:
urls, menus = get_menu(url_) # 获取目录信息
for index, url in enumerate(urls): # 遍历链接
f.write(f"==============={menus[index]}===============\n")
print(f"正在下载:{menus[index]}")
content = get_content(url) # 获取详细信息
f.write(content + "\n") # 写入文件
print(f"{menus[index]},下载完成") # 提示信息
print("--------------------------")
def main():
name = input("请输入要下载的小说名:")
save_data(search(name), name)
print("下载完成")
if __name__ == "__main__":
main()