python 小说 小说_python潇湘书院网站小说爬虫

很久没有写爬虫了,最近接到一个抓取小说的项目顺便做此纪录练练手,之后工作中可能也会有部分场景要用到爬虫,爬取竞争对手进行数据分析什么的。

b431200515652af470693f7e16d704b1.png

目标网站:潇湘书院

环境准备:

python3

requests库

BeautifulSoup库

整体思路

抓取这个小说网站免费板块的所有内容,查看页面发现这个板块一共有6697页,每页有20本小说,那整体思路就是先抓取每页的20个小说名称和url,然后进入每本小说的阅读地址,拿到每一个章节的标题和url,抓取每章节的正文内容并写到本地txt文本中。

123

单页分析

这里请求使用requests,解析页面用非常方便的BeautifulSoup,在一个文章标题上右键检查,在高亮的这条a标签右键,copy selector,通过这条selector来定位BeautifulSoup解析后小说所在的位置。

55f52f674b7a41e95a418db258ae4be3.png

1

body > div.content > div > div > div.inner-mainbar > div.search-result > div.result-list > ul > li:nth-child(1) > div > h4 > a

其中li:nth-child(1)很明显是指这个小说在当前页面小说列表中排列第一个,我们想要本页面所有的20本小说,所以就删掉这个:nth-child(1),再将selector语句精简一下只要能定位到即可,如下:

1

div.result-list > ul > li > div > h4 > a

然后将它写入代码,print查看一下结果。

1

2

3

4

5

6

7

import requests,os

from bs4 import BeautifulSoup

webdata = requests.get('http://www.xxsy.net/search?vip=0&sort=2')

soup = BeautifulSoup(webdata.text,'lxml')

books = soup.select('div.result-list > ul > li > div > h4 > a')

print(books)

75f849b9806f796ed67208fa76f3230c.png

结果是一个列表,列表中有20个元素,分别对应的20个小说,我们想要的是每个元素中href后面的链接和小说的名字,用循环提取出来。

1

2

3

4

5

6

...

for book in books:

bookname = book.text

bookurl = 'http://www.xxsy.net' + book.get('href')

bookid = book.get('href').split('/')[-1].split('.')[0]

print(bookname,bookurl,bookid)

5293ffb14509f37dae8af5e31d0deb11.png

这样就很简单的拿到了单个页面20本小说的标题和url地址,可以看到上面我把地址中的一串数字用单独取出来了,这个数字其实就是小说对应的唯一ID,后面要用到。

章节分析

点击一个小说进入详情页面,切换至”作品目录”下可以看到所有的章节,这时候在一个章节上右键检查,跟上面方法一样,同样可以很简单的获取到该小说所有章节的名称和url地址以及章节ID。

54f8b58eacd659d77d2bcbea4bffbf43.png

为了在一篇文章介绍尽可能多的方法,这里我不用上面这个地方来获取章节信息,从另一个地方进入。点击“开始阅读”进入第一章节的正文,在页面的左边可以看到一个“目录”按钮,点看以后就能看到所有的章节名称了。然而在这些章节名称上右键发现当前页面禁用了鼠标右键功能,无法检查元素当然也就不能copy它的selector。

8cf4b8e08047f5d05d58620d28af90e7.png

这种按钮的点击肯定是向服务器发送了请求的,打开fiddler进行抓包,再次点击目录按钮,此时可以看到这个请求已经被成功捕获,点击这条请求查看详细信息,这个接口的功能就是查询所有的章节信息。

ab7e36b50bfb8898f92de41b92d25eb1.png

真实的请求地址是http://www.xxsy.net/partview/GetChapterListNoSub?bookid=945608&isvip=0,其中bookid就是我们前面找到的bookid,这里可以做成参数化依次传入其他小说的ID。

1

2

3

4

5

6

7

...

url = 'http://www.xxsy.net/partview/GetChapterListNoSub?bookid=945608&isvip=0'

titles = BeautifulSoup(requests.get(url).text,'lxml').select('ul > li > a')

for title in titles:

titlename = title.text #章节名称

titleurl = 'http://www.xxsy.net' + title.get('href') #章节地址

print(titlename,titleurl)

45cd4ac6f404feb733536e0bad334ca0.png

正文下载

上一步取到的titleurl是每一章节的阅读地址,直接requests请求并解析拿到正文内容

1

contents = BeautifulSoup(requests.get(titleurl).text, 'lxml').select('div#auto-chapter > p') #正文内容

317c01be6ba714f1fc1a5667c9579ce4.png

返回结果是一个列表,每一个元素是一个段落,将每一段内容前后无用的标签剔除并写到本地的txt文本,写入方式为a+,每次写入时在后面追加,不会覆盖之前的内容,文本自动按照前面获取到的小说名来命名。

1

2

3

4

5

6

...

for content in contents:

content = str(content).replace('

', '\n').replace('

', '')

f = open(path + '%s.txt' % bookname, 'a+')

f.write(content)

f.close()

291621b880299f06529b4d1866f3d2b6.png

到此为止三个步骤已经完成,可以顺利的爬下一个章节的内容了,现在通过几个for循环将这几个步骤整合,就可以源源不断的开始下载小说了。

13c10400b44e4075997c77ca847e1dc2.gif

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

#coding=utf-8

import requests,time,os

from bs4 import BeautifulSoup

path = r'C:\Users\lipei\Desktop\潇湘书院爬虫\小说\\' #本地存放小说的路径

def get_books(url):

webdata = requests.get(url,timeout=60)

soup = BeautifulSoup(webdata.text,'lxml')

books = soup.select('div.result-list > ul > li > div > h4 > a')

for book in books:

bookid = book.get('href').split('/')[-1].split('.')[0] #小说ID作为下一个请求ur中的参数

bookname = book.text #小说名称

bookurl = 'http://www.xxsy.net' + book.get('href') #小说url地址

if bookname+'.txt' in oldlists: #判断是否已经下载过,若存在则跳过

continue

else:

pass

print('=====================正在下载【' + bookname + '】=====================')

url = 'http://www.xxsy.net/partview/GetChapterListNoSub?bookid=%s&isvip=0' % bookid

titles = BeautifulSoup(requests.get(url,timeout=60).text,'lxml').select('ul > li > a')

for title in titles:

titleurl = 'http://www.xxsy.net' + title.get('href') #章节url地址

titlename = title.text #章节名称

# print(titlename,titleurl)

try:

f = open(path + '%s.txt' % bookname, 'a+') #章节名称写到txt文本

f.write('\n'*2 + titlename + '\n')

f.close()

except:

pass

contents = BeautifulSoup(requests.get(titleurl,timeout=60).text, 'lxml').select('div#auto-chapter > p')

for content in contents:

content = str(content).replace('

', '\n').replace('

', '')

try:

f = open(path + '%s.txt' % bookname, 'a+') #正文内容卸载txt文本,紧接在章节名称的下面

f.write(content)

f.close()

except:

pass

print(titlename + '[已下载]')

if __name__ == "__main__":

urls = ['http://www.xxsy.net/search?vip=0&sort=2&pn={}'.format(i) for i in range(6697)] #免费板块每一页的url通过最后的pn参数控制

global oldlists

oldlists = os.listdir(path) #爬虫开始之前检查当前目录已有的文件

for url in urls:

get_books(url)

#控制每天爬取的数量,达到要求后停止任务,通过任务开始前后目录中的文件数量相减来判断

newlists = os.listdir(path)

num = len(newlists) - len(oldlists)

if num >= 20:

print('今日任务下载完毕,今日下载小说%d本' % num)

break

else:

pass

写在最后

在测试过程中发现短时间持续请求该网站的话会可能被服务器拒绝,但是并没有封禁IP,这可能是这个网站唯一的反爬措施了,然而并没有卵用,将请求放在一个无限循环里面,若被拒绝就自动重连,连上以后跳出循环。

后面如果遇到封禁IP的网站再讲如何通过更换IP来规避。

1

2

3

4

5

6

7

...

while True:

try:

webdata = requests.get(url,timeout=60)

break #连接成功就跳出循环

except:

time.sleep(3)

如有失效,请留言告知丨转载请注明原文链接:python潇湘书院网站小说爬虫

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值