欢迎光临散文网 会员登陆 & 注册

Python实战案例——某点中文小说网小说爬取

2023-08-16 16:05 作者:T___T___  | 我要投稿

 前言

现在喜欢看小说的朋友越来越多了,但是每次都要到某个网站去看有很麻烦。特别是有时候回乡下老家,信号差数据网络用不了,有没有WIFI。所以,要是能提前把小说下载好就OK了。

准备

其实,没什么要准备的。爬虫经常用的那几个模块就OK了。今天只用到了三个模块,分别是requests、json和re。

开始正题

抓包

其实,爬虫的步骤都是非常固定的。第一步,还是抓包,随便选一本小说然后点击免费试读,小说的内容就呈现在我们面前了。点击目录,发现地址栏的地址并没有改变过,所以就是阿贾克斯请求了,直接在Fetch/XHR中找数据包。


 果不其然,在下面这个数据包中就找到了所有章节的json数据


层层展开,发现每个索引下面有这些内容

 


接下来就是寻找这些数据和每一章节的关系,我观察了三章的地址栏,很容易就找出了规律,和我之前做的那个音乐爬虫如出一辙。

第二章


第三章


第四章 


 大家很容易就发现了,这个地址的前面的所有字符都是没有改变的,唯一改变了的就是最后一个数据。而这个数据,大家仔细观察,也很容易发现,它就是我们上面那个数据包中的章节索引下面的id对应的值。那么这样一来,每个章节的地址解决了。

接下来,我们就要来到每个章节的详情页,来想办法得到这本小说的文本内容。


我在“全部”的第一个数据包中,就找到了小说的文本内容 


 到这里,我们可以停下来,回头看看。到现在,我们已经得到了哪些有用信息。

1.每个章节的地址即URL

2.每个章节详情页的小说文本内容在哪

接下来,我们要做的就是根据这个URL获得小说文本内容就OK了

敲代码

首先,就是请求目录页的数据包,然后通过目录页的数据包得到每个章节的URL。在这里有一个需要注意的点,就是这个网站进行了一定程度的反爬,如果你不带上请求头就请求不到数据。


 


请求的URL和请求头就如上图所示,这样就可以请求到数据了。大家注意一下bookId,大家使用的话直接输入这个bookId就可以正常使用了,也就是我刚才展示的每个章节URL的倒数第二个数据,也就是倒数第二个位置的那串数字,就是小说的ID。还有一个点,就是请求头中其实有很多经过加密的字段,如果加上这些字段,是请求不到数据的,我没有将它们截图进来。 请求代码如下:

bookId = input('bookId:') url = 'https://www.qidian.com/ajax/book/category?bookId={}&_csrfToken=mLzoQhBuJ9pPDdAm8VpBuvMFXCgQQAlhFrC9TuvU'.format(bookId) headers = {    'Accept':'application/json, text/plain, */*',    'Accept-Encoding':'gzip, deflate, br',    'Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',    'Connection':'keep-alive',    'Cookie':'_csrfToken=mLzoQhBuJ9pPDdAm8VpBuvMFXCgQQAlhFrC9TuvU; newstatisticUUID=1692151465_166373733; Hm_lvt_f00f67093ce2f38f215010b699629083=1692151469; fu=1381548093; _yep_uuid=ad752dda-9748-ea50-e98f-865f3b8bb989; _gid=GA1.2.1689446406.1692151469; supportwebp=true; supportWebp=true; trkf=1; qdrs=0%7C3%7C0%7C0%7C1; navWelfareTime=1692152350314; showSectionCommentGuide=1; qdgd=1; rcr=1036370336; bc=1036370336; e1=%7B%22pid%22%3A%22qd_P_mycenter%22%2C%22eid%22%3A%22qd_H_mall_bottomaddownload%22%2C%22l7%22%3A%22hddl%22%7D; e2=%7B%22l6%22%3A%22%22%2C%22pid%22%3A%22qd_p_qidian%22%2C%22eid%22%3A%22qd_A16%22%2C%22l1%22%3A3%7D; lrbc=1036370336%7C749524263%7C0; _gat_gtag_UA_199934072_2=1; traffic_utm_referer=https%3A%2F%2Flink.csdn.net%2F; Hm_lpvt_f00f67093ce2f38f215010b699629083=1692155018; _ga_FZMMH98S83=GS1.1.1692151469.1.1.1692155018.0.0.0; _ga_PFYW0QLV3P=GS1.1.1692151469.1.1.1692155018.0.0.0; _ga=GA1.2.2023067070.1692151469',    'Host':'www.qidian.com',    'Referer':'https://www.qidian.com/chapter/1023826840/573073457/',    'sec-ch-ua':'"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"',    'sec-ch-ua-mobile':'?0',    'sec-ch-ua-platform':'"Windows"',    'Sec-Fetch-Dest':'empty',    'Sec-Fetch-Mode':'cors',    'Sec-Fetch-Site':'same-origin',    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42',    'X-D':'0'} response = requests.get(url=url, headers=headers)

还有一个点,直接输出text会出现乱码,我们手动设置一下编码格式为utf-8

response.encoding = 'utf-8'

然后,就是用正则表达式来提取文本中的id值了,当然还有每个章节的名称。

ex = '{"uuid":.*?,"cN":"(.*?)","uT":.*?,"cnt":.*?,"cU":.*?,"id":(.*?),"sS":.*?}'data = re.findall(ex, response.text, re.S)

至此,咱们就得到了每个章节的URL和每个章节的名称了。

数据提取

接下来,咱们就要对每个章节的数据进行提取了。当然首先是要构成每个章节的URL,然后再对每个章节的URL进行请求。然后继续用正则表达式对小说文本进行提取,代码如下:

chapterUrlList = [] titleList = [] bookBodyList = []print("正在获取书籍内容,请耐心等待哦!")for i in data:    # 获取每一章的章名    title = i[0]    titleList.append(title)    # 获取每一章的链接地址    chapterUrl = 'https://www.qidian.com/chapter/{}/'.format(bookId) + i[-1] + '/'    chapterUrlList.append(chapterUrl)    # 用正则表达式获取每一章的内容    book = requests.get(url = chapterUrl)    ex1 = '<main .*?><p>(.*?)</p></main>'    bookBody = re.findall(ex1, book.text, re.S)    # 用replace替换掉小说文本中的一些特殊符号    body = bookBody[0].replace('\u3000\u3000', '\n')    body = body.replace('<p>', '')    body = body.replace('</p>', '')    # 将文本保存到列表中    bookBodyList.append(body)# 获取小说名字和小说作者等信息book_Info = requests.get(url = chapterUrl) ex2 = '<script id="vite-plugin-ssr_pageContext" type="application/json">(.*?)</script>'book_Info = re.findall(ex2, book_Info.text, re.S)[0] json_data = json.loads(book_Info)print(type(json_data)) bookName = json_data['pageContext']['pageProps']['pageData']['bookInfo']['bookName'] authorName = json_data['pageContext']['pageProps']['pageData']['bookInfo']['authorName']print("正在保存,马上就好哦!")


最后就是保存请求来下的小说文本了

with open('书名:'+bookName + '作者' + authorName + '.txt', 'w') as f:    for j in range(0, len(titleList)):       f.write(titleList[j])       f.write(':')       f.write(chapterUrlList[j])       f.write(bookBodyList[j])print("保存成功!")

 到这里咱们就大功告成了!

注意事项

1.就是网站进行了一定程度的反爬,但是请求头中又有一些进行了加密的参数,如果全部加上也请求不到数据;如果一个不加也请求不到数据。

2.其实最麻烦的一个点还是数据提取,我们有的小说文本内容中,有很多html的语法符号,我们有必要把它们给清理掉。

3.正则表达式其实不太好配对,也可能是我学艺不精。因为我们从响应中直接将html标准的代码复制过来,它其中包含有换行符之类的符号是显现不出来的。在我们配对的时候就无法配对这些限制字符了。


完整代码我会上到资源里面的,有兴趣的可以下载哦。


仅供学习使用,请不要用于违法犯罪。


Python实战案例——某点中文小说网小说爬取的评论 (共 条)

分享到微博请遵守国家法律