Python爬虫实战案例——某点小说爬取

前言

现在喜欢看小说的朋友越来越多了,但是每次都要到某个网站去看有很麻烦。特别是有时候回乡下老家,信号差数据网络用不了,有没有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标准的代码复制过来,它其中包含有换行符之类的符号是显现不出来的。在我们配对的时候就无法配对这些限制字符了。

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

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

猜你喜欢

转载自blog.csdn.net/qq_64241302/article/details/132319135