python爬虫怎么爬小说_python从爬虫基础到爬取网络小说实例

一.爬虫基础

1.1 requests类

1.1.1 request的7个方法

requests.request() 实例化一个对象,拥有以下方法

requests.get(url, *args)

requests.head() 头信息

requests.post()

requests.put()

requests.patch() 修改一部分内容

requests.delete()

url = "http://quanben5.com/n/doupocangqiong/6.html"headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36"}

r= requests.get(url, headers=headers)

data={"pinyin": "doupocangqiong","content_id": "4",

}

r= requests.post(url, data=data, headers=headers)

1.1.2*arg里面的参数

params 字典或者字节序列,作为参数增加到url中

data 字典字节序列文件对象, 放在url里面对应的地方

json 作为requests的内容

headers 字典 模拟服务头

cookies 字典 cookieJar

auth 元组

files 字典类型,传输文件

timeout 设定的超时时间

proxies 字典类型,设定访问代理服务器,可以增加登录认证 pxs={"http":"http://user:pass@10.10.1.1234"}

allow_redirects 默认True 是否允许重定向

stream 默认TRUE 获得数据立刻下载

verity 默认True 认证SSL证书开关

cert 本地SSL证书路径

1.2 BeautifulSoup类

soup = BeautifulSoup("","html.parser")

soup.prettify()

soup.find_all(name, attrs, recursive, string, **kwargs)

name: 标签名称

attrs: 属性

string: 检索字符串

soup.head

soup.head.contents 列表

soup.body.contents[1]

soup.body.children

soup.body.descendants

.parent

.parents

.next_sibling 下一个

.previous_sibling 上一个

.next_siblings 下一个所有 迭代

.previous_siblings 上一个所有

1.3 selenium

1 from selenium importwebdriver2 from selenium.webdriver.chrome.options importOptions3 importtime4

5

6 chrome_options =Options()7 chrome_options.add_argument('--headless')8 chrome_options.add_argument('--disable-gpu')9

10 d = webdriver.Chrome(chrome_options=chrome_options) #设置成不显示浏览器的模式

11 d.get('http://quanben5.com/n/dazhuzai/23241.html')12 time.sleep(2)13 print(d.page_source) #显示出的是加载完之后的内容

查找单个和多个元素

d.find_element_by_id

d.find_elements_by_id

元素交互

from selenium importwebdriver

d=webdriver.Chrome()

d.get('http://www.baidu.com')

inputText= d.find_element_by_id("kw")

inputText.send_keys("萝莉")

button= d.find_element_by_id("su")

button.click()

二.实战

首先要找到可以在线看小说的网页

这里我随便百度了一下,首先选择了一个全本5200小说网("https://www.qb5200.tw")

打开某小说章节目录表

https://www.qb5200.tw/xiaoshuo/0/357/

查看源代码

1522021-20181122034437413-1230384032.png

发现正文卷是在class为listmain的div下面的第二个dt标签里

之后的路径标签为a

ContractedBlock.gif

ExpandedBlockStart.gif

1 url_text = soup.find_all('div', 'listmain')[0] #找到第一个class=listmain的div标签

2 main_text = url_text.find_all('dt')[1] #找到下面的第二个dt标签

3 for tag inmain_text.next_siblings:4 try:5 url = ''.join(['https://', host, tag.a.attrs['href']])6 print('parsering', url)7 except:8 continue

找到每个章节的url

在随便打开一章

查看源代码为:

1522021-20181122034953652-1458795577.png

ContractedBlock.gif

ExpandedBlockStart.gif

1 def getHTMLText(url, headers={}):2 """

3 获取网站源码4 :param url:5 :return: class response6 """

7 if headers !={}:8 headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36"}9

10 #proxies = get_random_ip()

11 proxies ={}12 try:13 #print("start", url)

14 r = requests.get(url, proxies=proxies, headers=headers)15 r.raise_for_status()16 #r.encoding = r.apparent_encoding

17 #print('end', url)

18 returnr19 except:20 returnr.status_code21

22 defparseByQB5200(soup, host, f):23 """

24 在全本小说网的源码下爬取小说25 :param soup, host:26 :param f:27 :return:28 """

29 url_text = soup.find_all('div', 'listmain')[0]30 main_text = url_text.find_all('dt')[1]31 x =032 for tag inmain_text.next_siblings:33 time.sleep(1)34 try:35 url = ''.join(['https://', host, tag.a.attrs['href']])36 print('parsering', url)37 soup = BeautifulSoup(getHTMLText(url).text, "html.parser")38 passage = soup.find_all("div", "content")[0]39 title =passage.h1.string40 f.writelines(''.join([title, '\n']))41 passage = soup.find_all("div", "showtxt")[0]42 for i inpassage.descendants:43 if i.name != "br":44 st =i.string45 if st.strip().startswith('http') or st.strip().startswith('请记住本书'):46 continue

47 f.writelines(''.join([' ', st.strip(), '\n']))48 x += 1

49 print('%d.%s 下载完成' %(x, title))50 except:51 continue

52

53 defgetNovelUrls(url):54 """

55 通过小说的目录网址判断小说所在的网站56 并调用属于该网站的爬虫语句57 :param url:58 :return:59 """

60

61 response =getHTMLText(url)62 host = url.split('//')[1].split('/')[0]63 host_list ={64 "www.qb5200.tw": parseByQB5200,65 #"www.qu.la": parseByQuLa,

66 "quanben5.com": parseByQB567 }68 print(response)69 soup = BeautifulSoup(response.text, 'html.parser')70 with open('1.txt', 'w', encoding='utf8') as f:71 host_list[host](soup, host, f)72

73 if __name__ == '__main__':74 getNovelUrls("https://www.qb5200.tw/xiaoshuo/0/357/")

在全本5200爬取小说txt

问题在于

全本小说网("www.qb5200.tw")在这样的暴力获取下只允许爬3次,之后就403错误

本来以为是同一IP限制访问次数, 使用了IP代理之后发现问题依旧

猜测应该是跟请求头有关

因此加上了访问该网站时浏览器的所有请求头,并且把User-Agent设置为随机

ContractedBlock.gif

ExpandedBlockStart.gif

USER_AGENT_LIST =['MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23','Opera/9.20 (Macintosh; Intel Mac OS X; U; en)','Opera/9.0 (Macintosh; PPC Mac OS X; U; en)','iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)','Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)','iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0','Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)','Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)']

headers= {"User-Agent": random.choice(USER_AGENT_LIST),"Host": "www.qb5200.tw","Connection": "keep-alive","Pragma": "no-cache","Cache-Control": "no-cache","Upgrade-Insecure-Requests": "1","Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","Referer": "https://www.qb5200.tw/xiaoshuo/0/355/","Accept-Encoding": "gzip, deflate, br","Accept-Language": "zh-CN,zh;q=0.9","Cookie": "UM_distinctid=16736c47b1d8b-04bd85d2b5e8ab-50422618-144000-16736c47b1e1f2; bcolor=; font=; size=; fontcolor=; width=; CNZZDATA1260750615=1497982366-1542811927-%7C1542882690; fikker-7ZUK-qXIL=qDaKEBihatSNEFgtMlGVIKubCHYLi89J; fikker-7ZUK-qXIL=qDaKEBihatSNEFgtMlGVIKubCHYLi89J; fikker-Sbwr-GN9F=GbMX3HOhwvoDMxopLMGt3VWliXQIK0SP; fikker-Sbwr-GN9F=GbMX3HOhwvoDMxopLMGt3VWliXQIK0SP; fikker-yJ3O-W61D=UfinETMnCR38ADWZEl1KNHQRU2m81Fwb; fikker-yJ3O-W61D=UfinETMnCR38ADWZEl1KNHQRU2m81Fwb; fikker-rWK3-6KHs=T9T5b7lYVJReTQviPm2IdLPyHu83RwFM; fikker-rWK3-6KHs=T9T5b7lYVJReTQviPm2IdLPyHu83RwFM"}

随机请求头

解决问题.

三.使用ajax动态加载的实例:

全本5小说网("quanben5.com")

同样的方法搜索源代码

1522021-20181122035422183-1941664844.png

1522021-20181122035446888-697843057.png

然而发现了问题

给出的html页面只有一半的源码

因此按F12打开检查

1522021-20181122035538752-115773497.png

发现所有的文本存在这个xhr里

1522021-20181122035642858-1312472641.png

点击查看请求头信息

1522021-20181122035746927-867979340.png

发现是post请求

请求的url是/index.php?c=book&a=ajax_content

请求的数据在最下面的form表单里

打开网页源文件和js文件,搜索这些表单信息

分别在ajax.js里和源文件里找到了这些

1522021-20181122035934964-835108673.png

1522021-20181122040053504-1217419321.png

源文件里面的可以直接生成data数据表单

在ajax.js里可以知道rndval字段是当前时间,精确到毫秒

四.优化

采用了gvent进行异步IO处理,每一张网页保存在temp里面,最后将文件合成一个txt

加入了搜索功能,目前仅支持一个小说网站

代码如下:

ContractedBlock.gif

ExpandedBlockStart.gif

1 #!/usr/bin/env python

2 #encoding: utf-8

3

4 """

5 @version:6 @author: Wish Chen7 @contact: 986859110@qq.com8 @file: get_novels.py9 @time: 2018/11/21 19:4310

11 """

12 importgevent13 from gevent importmonkey14 monkey.patch_all()15 importrequests, time, random, re, os16 from bs4 importBeautifulSoup17

18 dir = os.path.dirname(os.path.abspath(__file__))19

20 def getHTMLText(url, data=[], method='get'):21 """

22 获取网站的源代码23 请求默认为get24 :param url:25 :param data:26 :param method:27 :return:28 """

29 headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36"}30 proxies ={}31 try:32 #print("start", url)

33 r = requests.request(method, url, proxies=proxies, headers=headers, data=data)34 r.raise_for_status()35 #r.encoding = r.apparent_encoding

36 #print('end', url)

37 returnr38 except:39 returnr.status_code40

41

42 deffetch_async(x, url):43 """

44 异步IO所需要执行的操作45 获取源文件46 模拟向ajax请求获取完整文字47 每一章输入到temp文件夹下48 :param x:49 :param url:50 :return:51 """

52 url_main = "http://quanben5.com/index.php?c=book&a=ajax_content"

53 r = getHTMLText(url) #获取每一章的源文件

54 title = re.search(r'

(.*)

', r.text).group(1)55 result = re.search(r'', r.text).group(1)56 num_list = result.split("','")57 num_list[9] = num_list[9][:-1]58 content = {} #开始模拟post请求发送的表单

59 for i in range(1, 5):60 content[num_list[i * 2]] = num_list[i * 2 + 1]61 content['_type'] = "ajax"

62 content['rndval'] = int(time.time() * 1000)63 r = getHTMLText(url_main, data=content, method='post') #模拟post请求

64 soup = BeautifulSoup(r.text, "lxml")65 with open(os.path.join(dir, 'temp', "%s.txt" % x), "w", encoding='utf8') as f:66 f.writelines(''.join([str(x), '.', title, '\n\n']))67 for tag insoup.body.children:68 if tag.name == 'p':69 f.writelines(''.join([' ', tag.string.strip(), '\n\n']))70 print('%d.%s 下载完成' %(x, title))71

72

73 defget_together(name, author, x):74 """

75 将temp目录下的各网页下载下来的txt76 合并在一起77 并删除temp文件78 :param name:79 :param author:80 :return:81 """

82 with open(os.path.join(dir, "%s.txt" % name), "w", encoding='utf8') as f:83 f.writelines(''.join([name, '\n\n作者:', author, '\n\n']))84

85 for i inrange(x):86 try:87 f.write(open(os.path.join(dir, 'temp', "%s.txt" % (i+1)), "r", encoding='utf8').read())88 f.write('\n\n')89 #os.remove(os.path.join(dir, 'temp', "%s.txt" % (i+1)))

90 except:91 continue

92

93

94 defparseByQB5(response, host):95 """

96 在全本5小说网的源码下爬取小说97 获得书名和作者98 采用gevent异步IO优化99 :param response:100 :param host:101 :return:102 """

103 soup = BeautifulSoup(response.text, 'html.parser')104 url_text = soup.find_all('div', 'box')[2]105 main_text = url_text.find_all('h2')[0].next_sibling106 url_list =[]107 for tag inmain_text.descendants:108 if tag.name == 'li':109 url = ''.join(['http://', host, tag.a.attrs['href']])110 url_list.append(url)111 from gevent.pool importPool112 pool = Pool(100)113

114 gevent.joinall([pool.spawn(fetch_async, i+1, url=url_list[i]) for i inrange(len(url_list))])115

116 name = re.search(r"

(.*)

", response.text).group(1)117 author = re.search(r' (.*)', response.text).group(1)118 print("%d文档已下载,正在合并..." %len(url_list))119 get_together(name, author, len(url_list))120

121

122 defgetNovelUrls(url):123 """

124 通过小说的目录网址判断小说所在的网站125 并调用属于该网站的爬虫语句126 :param url:127 :return:128 """

129

130 response =getHTMLText(url)131 host = url.split('//')[1].split('/')[0]132 host_list ={133 "quanben5.com": parseByQB5134 }135 host_list[host](response, host)136

137

138 defget_url():139 input_name = input('>>')140 r = getHTMLText("http://quanben5.com//index.php?c=book&a=search&keywords=%s" %input_name)141 soup = BeautifulSoup(r.text, "html.parser")142 main_book = soup.find_all("div", "pic_txt_list")143 for i inrange(len(main_book)):144 tag =main_book[i].h3145 print("%s.%s %s" %(i, tag.span.text, tag.next_sibling.next_sibling.text))146 choice = int(input(">>"))147 if choice inrange(len(main_book)):148 return ''.join(["http://quanben5.com", main_book[choice].h3.a["href"], "xiaoshuo.html"])149

150

151 if __name__ == '__main__':152 #url_list = [

153 #"https://www.qu.la/book/365/",

154 #"https://www.qb5200.tw/xiaoshuo/0/357/",

155 #"http://quanben5.com/n/doupocangqiong/xiaoshuo.html",

156 #"http://quanben5.com/n/dazhuzai/xiaoshuo.html",

157 #"http://quanben5.com/n/douluodalu/xiaoshuo.html",

158 #"http://quanben5.com/n/renxingderuodian/xiaoshuo.html"

159 #]

160 #if not os.path.exists('temp'):

161 #os.mkdir('temp')

162 #getNovelUrls(url_list[5])

163 whileTrue:164 url =get_url()165 time_start =time.time()166 getNovelUrls(url)167 print("成功爬取! 用时:%ds" % (int((time.time()-time_start)*100)/100))

异步IO+搜索

封装性还不够好

最好一个网站用一个类来封装

采用scrapy框架

正在设计中...

五.未解决问题:

代理IP问题:

目前只有免费的代理IP网

生成随机IP并使用代理IP访问

多网站定制

要观察各个网站的目录源代码结构以及文章源代码结构

每一个网站都可以用一个parse函数来解析其内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值