python爬虫案例 |
您所在的位置:网站首页 › python爬取小说内容 › python爬虫案例 |
提示:此文章及爬虫代码仅供学习交流,请勿用于他处。 前言在写爬虫的时候,我们用requests抓取页面,获得的HTML文本可能和浏览器上看到的不一样,原因是requests请求得到的是HTML源文档,而浏览器显示的内容可能是通过JavaScript渲染而成的,Ajax异步加载的数据也是通过JavaScript渲染后呈现在浏览器上。 本文以爬取百度小说为案例,分析如何爬取Ajax异步加载的内容。 爬虫实现过程爬取的小说:《冰川天女传》 URL地址:http://dushu.baidu.com/pc/detail?gid=4345224252 我们直接从小说界面开始,从小说的目录下手,如下图所示: 用requests库请求这个网站 url = 'http://dushu.baidu.com/pc/detail?gid=4345224252' res = requests.get(url) print(res.text)我们看一下返回的HTML网页中标签里面的内容: 标签里面什么也没有,说明我们想要的小说内容并不在HTML源文档里面,那么它可能就是JavaScript加载的。我们就通过浏览器开发者工具来分析一下吧。 按F12键进入调试界面,点击Network选项卡,再点击XHR。 我们查看一下上面两个请求的的Response,里边的内容都是大括号 { } 括起来的内容,它是JSON格式的内容,点击Preview可以更为直观地展示里边的内容。(如果不知道JSON格式的话,可以先百度一下。) 仔细看一下JSON格式的内容,不难发现,真的可以找到了小说的目录,看图: 现在我们已经知道,小说的内容包括在浏览器看到的这8个章节目录,都是通过Ajax异步加载的方式加载的,然后通过JavaScript显示出来。 现在点击页面上的 “查看全部” ,把全部章节显示出来。 这时,XHR又多了一个请求,可以断定,这个新的请求包括了所有章节目录的内容。 如下图所示: 这时,我们点击一下Header看一下这个请求的头部信息,找到这个请求的 URL: 分析一下这个URL:%22是经过编码的内容,把他进行解码之后它是英文的双引号。 也就是说,整个URL其实长这样: http://dushu.baidu.com/api/pc/getCatalog?data={“book_id”:“4345224252”} 有book_id字样,冒号后面还有一串数字。 在文章开始,我们说要爬取《冰川天女传》这部小说,这部小说的URL是http://dushu.baidu.com/pc/detail?gid=4345224252,现在我们知道了,这个 gid= 后面的数字就是这本小说的 book_id 值,通过这个 book_id 就可以找到这本小说了。 请看代码,根据原来的URL构造新的URL: url = 'http://dushu.baidu.com/pc/detail?gid=4345224252' index = url.find('gid=') book_id = url[index+4:] novel_url = 'http://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"%s"}'%book_id接下来请求novel_url 这个链接,就可以得到刚刚得到的JSON格式的数据了。 JSON格式的数据和访问python字典的方式是一样的,请看: data = requests.get(novel_url).json() for item in data['data']['novel']['items']: cid = item['cid'] print(cid)
可以猜测,章节的文本内容也是通过Ajax加载的,所以尝试用刚刚的方法看看能不能找到一些端倪。 果不其然,当我们在浏览器页面点开其中一个章节之后,Network中的XHR果然出现了小说的文本内容。
解码之后比较好看:http://dushu.baidu.com/api/pc/getChapterContent?data={“book_id”:“4345224252”,“cid”:“4345224252|1561658660”,“need_bookinfo”:1} 通过这个URL我们也可以发现其中的规律,主要看data=后面的内容,通过 book_id 和 cid 就可以构建出来。 构造小说章节URL,访问这个URL,解析JSON文件得到小说文本内容啦 data = requests.get(novel_url).json() for item in data['data']['novel']['items']: cid = item['cid'] content_url = 'http://dushu.baidu.com/api/pc/getChapterContent?data={%22book_id%22:%22' + book_id \ + '%22,%22cid%22:%224345224252|' + cid + '%22,%22need_bookinfo%22:0}' content = requests.get(content_url).json() print(content['data']['novel']['content']) break搞定!!! 总结一下如何获取Ajax异步加载的内容。 既然是异步加载,说明它通常是跟人进行交互才会加载出来,那么我们就可以通过分析Network中的XHR里面的请求内容,看看浏览器请求了哪些内容,一步一步分析,通常在这些内容里面就可以找到我们想要爬取的内容了。 完整代码 import requests import time # url:小说界面的链接 url = 'http://dushu.baidu.com/pc/detail?gid=4345224252' index = url.find('gid=') book_id = url[index+4:] novel_url = 'http://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"%s"}'%book_id data = requests.get(novel_url).json() fp = open('novel.txt', 'w', encoding='utf-8') for item in data['data']['novel']['items']: if item.get('price_status') == '0': n_title = item.get('title') n_cid = item.get('cid') last_url = 'http://dushu.baidu.com/api/pc/getChapterContent?data={%22book_id%22:%22' + book_id \ + '%22,%22cid%22:%224345224252|' + n_cid + '%22,%22need_bookinfo%22:0}' content = requests.get(last_url).json()['data']['novel']['content'] fp.write(n_title + '\n\n') fp.write(content + '\n\n\n') print('成功爬取:', n_title) time.sleep(0.5) elif item.get('price_status') == '1': n_title = item['title'] print('付费章节,无法爬取:', n_title) fp.close()以下代码经过函数封装,输入小说名字就可以进行下载。 (写得比较急,代码不太优美,但功能已经实现) import requests import time def novel_crawler(_novelName): resultList = [] start_url = 'http://dushu.baidu.com/api/pc/getSearch?data={%22word%22:%22' + _novelName + '%22,%22pageNum%22:1}' searchResult = requests.get(start_url).json() totalNum = searchResult.get('data').get('total') if totalNum == '0': print('未找到该小说,请尝试修改搜索词') book_id = book_name = None return elif totalNum == '1': resultList += searchResult.get('data').get('list') print('找到1本小说:\n{0}({1}著)'.format(resultList[0].get('book_name'), resultList[0].get('author'))) input('回车之后即可下载') book_name = resultList[0].get('book_name') book_id = resultList[0].get('book_id') elif eval(totalNum) > 9: print('共搜索到%s本小说,如下:' % totalNum) for page in range(1,int(eval(totalNum)/10)+2): start_url = 'http://dushu.baidu.com/api/pc/getSearch?data={%22word%22:%22' + _novelName +\ '%22,%22pageNum%22:'+str(page)+'}' searchResult = requests.get(start_url).json() resultList += searchResult.get('data').get('list') for li in range((page-1)*10,len(resultList)): # liNum = (page-1)*10+li liNum = li print('{0}.{1}({2}著)'.format(liNum, resultList[liNum].get('book_name'), resultList[liNum].get('author'))) if liNum%10 = len(resultList) or listNo int(totalNum) - 1 or listNo |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |