python爬虫
爬虫概念:按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。
通俗的来说就是:就是爬虫可以模拟浏览器的行为做你想做的事,订制化自己搜索和下载的内容,并实现自动化的操作。
爬虫实现: 实现爬虫技术的编程环境有很多种,Java,Python,C++等都可以用来爬虫
爬虫包含6个模块:
- url管理器
- download下载器
- parser解析器
- output导出数据
- crawler爬虫调度器
- useragent代理池
爬虫学习知识点:
1、首先学会基本的Python语法知识
2、学习Python爬虫常用到的几个重要内置库urllib, http等,用于下载网页
3、学习正则表达式re、BeautifulSoup(bs4)、Xpath(lxml)等网页解析工具
4、开始一些简单的网站爬取(博主从百度开始的,哈哈),了解爬取数据过程
5、了解爬虫的一些反爬机制,header,robot,时间间隔,代理ip,隐含字段等
6、学习一些特殊网站的爬取,解决登录、Cookie、动态网页等问题
7、了解爬虫与数据库的结合,如何将爬取数据进行储存
8、学习应用Python的多线程、多进程进行爬取,提高爬虫效率
9、学习爬虫的框架,Scrapy、PySpider等
10、学习分布式爬虫(数据量庞大的需求)
一个请求过程:在浏览器输入网址搜索后----->DNS服务器进行域名解析----->找到对应服务器并通过GET或POST方法请求数据----->
- ---->若请求成功,我们就得到了我们想看到的网页----->
---->若请求不成功,服务器会返回给我们请求失败的状态码,常见到的503,403等。
爬虫的原理:Python爬虫通过URL管理器,判断是否有待爬URL,如果有待爬URL,通过调度器进行传递给下载器,下载URL内容,并通过调度器传送给解析器,解析URL内容,并将价值数据和新URL列表通过调度器传递给应用程序,并输出价值信息的过程;
爬虫的基本流程,主要可以分为三部分:
- 获取网页
- 解析网页(提取数据)
- 存储数据
爬虫相关的包与工具
- 一些爬虫工具:Octoparse、Cyotek WebCopy、HTTrack、Getleft、Scraper等;
- 获取网页:request、urllib、selenium | 多进程多线程抓取、登陆抓取、突破IP封锁、服务器抓取;
- 解析网页:re正则表达式、BeautifulSoup、Ixml | 解决中文乱码
- 存储数据:存入txt文件、存入csv文件 | 存入数据库
python请求:urllib库:向服务器发出请求并获得网页的功能
Python2.x中使用的urllib2和urllib库,而Python3.x中合并成一个唯一的urllib库。
python属性:error,parse,request,response。
1、Error:“Exception classesraised by urllib.”----就是由urllib举出的exception类
2、Parse:“Parse (absolute andrelative) URLs.”----解析绝对和相对的URLs
3、Request:“An extensiblelibrary for opening URLs using a variety of protocols”
----用各种协议打开URLs的一个扩展库
4、Response:“Response classesused by urllib.”----被urllib使用的response类
一个简单例子:获取python网页
import urllib.request response = urllib.request.urlopen('http://python.org/') result = response.read().decode('utf-8') print(result)
其中urlopen方法
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TI MEOUT,*, cafile=None, capath=None, cadefault=False, context=None):
参数介绍:
url:即是我们输入的url网址,(如:http://www.xxxx.com/);
data: 是我们要发给服务器请求的额外信息(比如登录网页需要主动填写的用户信息)。如果需要添加data参数,
那么是POST请求,默认无data参数时,就是GET请求;
一般来讲,data参数只有在http协议下请求才有意义
data参数被规定为byte object,也就是字节对象
data参数应该使用标准的结构,这个需要使用urllib.parse.urlencode()将data进行 转换,
而一般我们把data设置成字典格式再进行转换即可;data在以后实战中会介绍如何使用
timeout:是选填的内容,定义超时时间,单位是秒,防止请求时间过长,不填就是默认的时间;
cafile:是指向单独文件的,包含了一系列的CA认证 (很少使用,默认即可);
capath:是指向文档目标,也是用于CA认证(很少使用,默认即可);
cafile:可以忽略
context:设置SSL加密传输(很少使用,默认即可);
打开链接后其他操作:
geturl(): 返回URL,用于看是否有重定向。 result = response.geturl() 结果: https://www.python.org/
info():返回元信息,例如HTTP的headers。 result = response.info() 结果: x-xss-protection: 1; mode=block X-Clacks-Overhead: GNU Terry Pratchett ... Vary: Cookie Strict-Transport-Security: max-age=63072000;includeSubDomains
getcode():返回回复的HTTP状态码,成功是200,失败可能是503等,可以用来检查代理IP的可使用性。 result = response.getcode() 结果:200
Request方法 class Request: def __init__(self, url, data=None, headers={},origin_req_host=None, unverifiable=False,method=None):
参数介绍:
url,data和上面urlopen中的提到的一样。
headers是HTTP请求的报文信息,如User_Agent参数等,它可以让爬虫伪装成浏览器而不被服务器发现你正在使用爬虫。
origin_reg_host, unverifiable, method等不太常用
headers很有用,有些网站设有反爬虫机制,检查请求若没有headers就会报错,
因此为保证爬虫的稳定性,基本每次都会将headers信息加入进去,这是反爬的简单策略之一
import urllib.request headers = {'User_Agent': ''} response = urllib.request.Request('http://python.org/', headers=headers) html = urllib.request.urlopen(response) result = html.read().decode('utf-8') print(result)
error的使用:error属性里面主要包括了两个重要的exception类,URLError类和HTTPError类。
1. URLError类 def __init__(self, reason, filename=None): self.args = reason, self.reason = reason if filename is not None: self.filename = filename URLError类是OSError的子类,继承OSError,没有自己的任何行为特点,但是将作为error里面所有其它类型的基类使用。 URLError类初始化定义了reason参数,意味着当使用URLError类的对象时,可以查看错误的reason。
2. HTTPErro类 def __init__(self, url, code, msg, hdrs, fp): self.code = code self.msg = msg self.hdrs = hdrs self.fp = fp self.filename = url HTTPError是URLError的子类,当HTTP发生错误将举出HTTPError。 HTTPError也是HTTP有效回应的实例,因为HTTP协议错误是有效的回应,包括状态码,headers和body。所以看到在HTTPError初始化的时候定义了这些有效回应的参数。 当使用HTTPError类的对象时,可以查看状态码,headers等
案例1: import urllib.request import urllib.error try: headers = {'User_Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0'} response = urllib.request.Request('http://python.org/', headers=headers) html = urllib.request.urlopen(response) result = html.read().decode('utf-8') except urllib.error.URLError as e: if hasattr(e, 'reason'): print('错误原因是' + str(e.reason)) except urllib.error.HTTPError as e: if hasattr(e, 'code'): print('错误状态码是' + str(e.code)) else: print('请求成功通过。')
项目实战:
import requests # 发送请求 from lxml import etree # 数据解析 import time # 线程暂停,怕封ip import os # 创建文件夹 # 由于目标网站更新了反爬虫机制,简单的UA伪装不能满足我们的需求,所有对整个消息头进行了伪装 headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Cache-Control': 'max-age=0', 'Connection': 'keep-alive', 'Cookie': '__gads=undefined; Hm_lvt_aecc9715b0f5d5f7f34fba48a3c511d6=1614145919,1614755756; ' 'UM_distinctid=177d2981b251cd-05097031e2a0a08-4c3f217f-144000-177d2981b2669b; ' 'sctj_uid=ccf8a73d-036c-78e4-6b1d-6035e961b0d3; ' 'CNZZDATA300636=cnzz_eid%3D1737029801-1614143206-%26ntime%3D1614759211; ' 'Hm_lvt_398913ed58c9e7dfe9695953fb7b6799=1614145927,1614755489,1614755737; ' '__gads=ID=af6dc030f3c0029f-226abe1136c600e4:T=1614760491:RT=1614760491:S=ALNI_MZAA0rXz7uNmNn6qnuj5BPP7heStw; ' 'ASP.NET_SessionId=3qd454mfnwsqufegavxl5lbm; Hm_lpvt_398913ed58c9e7dfe9695953fb7b6799=1614760490; ' 'bbsmax_user=ce24ea68-9f80-42e3-8d4f-53b13b13c719; avatarId=a034b11b-abc9-4bfd-a8b2-bdf7fef644bc-; ' 'Hm_lpvt_aecc9715b0f5d5f7f34fba48a3c511d6=1614756087', 'Host': 'sc.chinaz.com', 'If-None-Match': '', 'Referer': 'https://sc.chinaz.com/jianli/free.html', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0', } # 如果该文件夹不存在,则创建文件夹 if not os.path.exists('E:\moban'): os.mkdir('E:\moban') for i in range(2, 701): # 预计可爬700*20套简历模板 print(f"正准备爬取第{i}页简历模板") print("怕封ip,操作暂停中......") # 操作暂停提示语 time.sleep(15) # 每获取一个列表页暂停15s,一个列表页有20分简历模板的链接 url = f'https://sc.chinaz.com/jianli/free_{str(i)}.html' # 设置相应的路由i try: # 异常处理 response = requests.get(url=url, headers=headers) # 获取响应 except Exception as e: # 给异常取名为e print(e) # 打印异常名称 print('连接失败,选择跳过!!!') # 连不上就不要连了,头铁容易出事 print("怕封ip,获取列表页操作暂停中......") # 操作暂停提示语 time.sleep(5) # 每出现一次异常暂停5s continue # 跳过本次循环 response.encoding = 'utf-8' # 中文编码为utf-8 page = response.text # 获取响应的文本数据 tree = etree.HTML(page) # 用etree进行数据解析 a_list = tree.xpath("//div[@class='box col3 ws_block']/a") # 用xpath提取目标内容形成20份一起的列表
for a in a_list: resume_href = 'https:' + a.xpath('./@href')[0] # 根据爬取的链接设置新的网页 resume_name = a.xpath('./img/@alt')[0] # 爬取名字,并对列表进行切片取第一个 resume_name = resume_name.strip() # 去掉首尾的空格 try: resume_response = requests.get(url=resume_href, headers=headers) # 进入简历模板详情页面 except Exception as e: print(e) print('连接失败,选择跳过!!!') print("怕封ip,获取个人简历详情页操作暂停中......") time.sleep(5) continue resume_response.encoding = 'utf-8' # 中文编码为utf-8 resume_page = resume_response.text # 获取响应的文本数据 resume_tree = etree.HTML(resume_page) # 用etree进行数据解析 resume_link = resume_tree.xpath('//ul[@class="clearfix"]/li/a/@href')[0] # 用xpath提取目标内容的下载链接 try: download = requests.get(url=resume_link, headers=headers).content # 获取二进制数据 except Exception as e: print(e) print('连接失败,选择跳过!!!') print("怕封ip,下载个人简历操作暂停中......") time.sleep(5) continue download_path = 'E:\moban' + resume_name + '.zip' # 设置保存路径以及文件名称 with open(download_path, 'wb') as fp: # 设置文件制作,以二进制形式 fp.write(download) # 保存文件 print(resume_name, '下载成功!!!') # 下载成功提示语
本文转载:https://segmentfault.com/a/1190000012681700、