[TOC]
了解爬虫 网络爬虫的分类
通用网络爬虫:抓取系统重要组成部分,抓取的是一整张页面。搜索引擎使用,遵守robopts协议。(robots协议是君子协议,只防君子,不防小人。)
聚焦网络爬虫:又称主题网络爬虫,根据预定义的主题来进行相关页面的爬取(抓取局部),与通用网络爬虫想比,它的爬取范围更为精准(自己写的爬虫程序)
增量式网络爬虫: 对已下载网页采取增量式更新和只爬行新产生的或者已经发生变化网页的爬虫。
深层网络爬虫: Web 页面按存在方式可以分为表层网页和深层网页,深层网页是指大多内容不能通过静态获取,需要用户提交关键词才能获取到隐藏在搜索表单后面的内容。
爬取数据的步骤:
发送请求:确定需要爬取的URL地址
获取响应内容:由请求模块向URL地址发出请求,并得到网站的响应
解析内容:利用解析模块从响应内容中提取所需数据
保存数据
爬虫入门 URL 1 protocol :// hostname[:port ] / path / [;parameters ][?query ]#fragment
URL 由三部分组成,第一部分是协议 ,有http、https、ftp等,第二部分存放资源的服务器的域名或IP地址 ,第三部分为资源的具体地址 。
我们在进行网络请求的时候通常采用三种方式:urllib、urllib3 和 requests,下面我们就来介绍一下 urllib 和 requests。
网络请求
请求模块是urllib.request,是Python标准库模块。
模块导入 程序的导入方式:
import urllib.request
from urllib import request
模块内的方法
urllib.request.urlopen(URL,timeout)
作用:向网站发起请求并且获取响应对象。
参数
作用
URL
需要爬取的URL地址
timeout
设置等待超时时间,指定时间未响应抛出异常
响应对象(res)的方法
方法
作用
res.read()
获取响应内容(字节串)
res.read().decode()
获取响应内容(字符串)
res.geturl()
返回实际数据的URL地址
res.getcode()
获取HTTP响应代码
字节串
什么是字节串 python 中的bytes 类型用来表示一个字节串。他是python3.x新加的类型(对比python2.x)。
bytes 只负责以字节序列的形式(二进制形式)来存储数据,至于这些数据到底表示什么内容(字符串、数字、图片、音频等),完全由程序的解析方式决定。如果采用合适的字符编码方式(字符集),字节串可以恢复成字符串;反之亦然,字符串也可以转换成字节串。bytes 类型的数据非常适合在互联网上传输,可以用于网络通信编程;bytes 也可以用来存储图片、音频、视频等二进制格式的文件。
字节串(bytes)和字符串(string)的对比:
字符串由若干个字符组成,以字符为单位进行操作;字节串由若干个字节组成,以字节为单位进行操作。 字节串和字符串除了操作的数据单元不同之外,它们支持的所有方法都基本相同。 字节串和字符串都是不可变序列,不能随意增加和删除数据。
举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from urllib import requestres = request.urlopen(url='https://www.baidu.com' ) html = res.read().decode() url = res.geturl() code = res.getcode() print (res)print (url)print (code)
结果如下:
requests 模块
requests是一种**第三方模块**,主要用于发送请求,它在使用的时候比urllib模块要简洁方便很多,我们可以在命令操作符里通过pip install requests来安装,也可以在Pycharm中直接进行安装。
requests 模块也可以使用 get, post, put, delete, hand 等来发送请求。
我们以 get 方法为例;
1 2 3 4 5 6 7 import requestsr = requests.get('https://www.douban.com/' ) print (r.status_code) print (r.encoding) print (r.headers) print (r.cookies) print (r.content)
注意: 在开启代理(或者说科学上网后),会报错。请把 https 改成 http ;或者关闭掉代理。
伪装成用户 网站是如何判断是正常人类访问还是爬虫访问?
通过请求头(headers)中的User-Agent来判断。
所以我们应该修改User-Agent,具体如下:
使用url.request.Request()方法:
创建请求对象
包装请求,重构User-Agent
常用参数: URL:请求的URL地址
headers:添加请求头,类型为字典headers = {‘User-Agent’: ‘ ‘}
字典的值该填什么呢?
打开浏览器 —> F12 (Ctrl+Shift+I) —> network (网络) —> 刷新 —> 点击一个 —> 下划找到 User-Agent 。把值填入字典即可。
代码如下:
1 2 3 4 5 6 7 8 from urllib import requestreq = request.Request(url = url,headers=headers) res = request.urlopen(req) html = res.read().decode()
实例
1 2 3 4 5 6 7 8 9 10 11 from urllib import requesturl='http://httpbin.org/get' headers={'User-Agent' :'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1' } req=request.Request(url=url,headers=headers) res=request.urlopen(req) html=res.read().decode() print (html)
网络超时处理 我们在发送网络请求的时候避免不了超时现象的发生,如果我们不设置一个超时时间,那么系统会因为它长时间未响应而无法打开网页。
超时又分为连接超时 和读取超时 。
连接超时就是在程序默认的等待时间内没有得到服务器的响应。
1 2 3 4 5 6 7 8 9 10 11 import datetimeimport requestsurl = 'http://www.google.com.hk' print (datetime.datetime.now())try : r = requests.get(url, timeout = 5 ).text print ('获得响应' ) except requests.exceptions.RequestException as s: print ('连接超时' ) print (s) print (datetime.datetime.now())
结果如下:
1 2 3 4 2022-11-12 22:08:55.395394 连接超时 HTTPConnectionPool(host='www.google.com.hk', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x0000016A5EEA3520 > , 'Connection to www.google.com.hk timed out. (connect timeout=5)')) 2022-11-12 22:09:00.539448
读取限定时间:
1 r = requests.get(url, timeout=(5 ,10 )).text
在这里15即为读取限制时间,如果超过即为读取超时。
URL的一些处理
给URL地址中查询参数进行编码
导入方式:
1 2 import urllib.parsefrom urllib import parse
url不能识别中文,需要编码进行转换
1 2 3 params = {'word' :'小璇' ,'pn' :'50' } params = urllib.parse.urlencode(params) print (params)
结果如下:
拼接URL地址的三种方式
练习: 百度搜索”小璇”,并且保存到本地
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from urllib import requestfrom urllib import parseword = input ('请输入百度搜索关键字:' ) params=parse.urlencode({'wd' :word}) url='http://www.baidu.com/s?{}' .format (params) headers={'User-Agent' :'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1' } req=request.Request(url=url,headers=headers) res=request.urlopen(req) html=res.read().decode() print (html)filename=word+'.html' with ope(filename,'w' ,encoding='utf-8' ) as f: f.write(html)
百度贴吧爬虫案例 步骤
代码如下:
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 from urllib import requestfrom urllib import parseimport timeclass BaiduTiebaSpider : def __init__ (self ): self.ur1 = 'http://tieba.baidu.com/f?kw={}&pn={}' self.headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1' } def get_html (self, url ): req = request.Request(url=url, headers=self.headers) res = request.urlopen(req) html = res.read().decode() return html def parse_html (self ): """解析提取数据的函数""" pass def save_html (self, filename, html ): with open (filename, 'w' , encoding='utf8' ) as f: f.write(html) def run (self ): name = input ('请输入贴吧名:' ) start = int (input ('请输入起始页:' )) end = int (input ('请输入终止页:' )) params = parse.quote(name) for page in range (start, end + 1 ): pn = (page - 1 ) * 50 url = self.ur1.format (params, pn) html = self.get_html(url) filename = '{}_第{}页.html' .format (name, page) self.save_html(filename, html) print ('第%d页抓取成功' % page) time.sleep(random.randint(1 , 3 )) test = BaiduTiebaSpider() test.run()
爬取笔趣阁小说案例 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 62 63 64 65 66 67 68 69 70 71 72 73 74 import requestsfrom bs4 import BeautifulSoupimport timeimport lxmlfirst_url = 'https://www.bqg99.com/book/944/' basic_url = { 'whole' : None , 'index' : 1 } custom_header = { 'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35' } output = 'D:/studyProject/myNote/novel.txt' def update_link (url_dict ): url_dict['whole' ] = first_url + str (url_dict['index' ]) + '.html' url_dict['index' ] = url_dict['index' ] + 1 print (url_dict['whole' ]) return url_dict def fetch_text (url_dict, request_header ): data = requests.get(url=url_dict['whole' ], headers=request_header, allow_redirects=False ) print ('status = %d' % data.status_code) if data.status_code == 302 : return None else : data = BeautifulSoup(data.text, 'lxml' ) article = data.find(name='div' , class_='content' ) chapter_topic = article.h1.text content_soup = article.find(name='div' , id ='chaptercontent' , class_='Readarea ReadAjax_content' ) content_soup.p.decompose() charter_words = content_soup.stripped_strings chapter = { 'topic' : chapter_topic, 'content' : charter_words } return chapter def main (): novel = open (file=output, mode='a+' , encoding='utf8' ) link = update_link(basic_url) text = fetch_text(url_dict=link, request_header=custom_header) while text is not None : novel.write(text['topic' ]) novel.write('\n' ) for line in text['content' ]: line = line novel.write(line) novel.write('\n' ) novel.write('\n\n' ) time.sleep(1 ) link = update_link(link) text = fetch_text(url_dict=link, request_header=custom_header) novel.close() if __name__ == '__main__' : main()
参考文章:
[1]: https://blog.csdn.net/m0_46213598/article/details/119704825 “python爬虫快速入门” [2]: https://www.dotcpp.com/course/318 “Python爬虫技术基础” [3]: https://www.52pojie.cn/thread-1710198-1-1.html “笔趣阁小说爬虫下载”