Python3爬虫1
编程语言
2018-11-26 12:49:32
阅读次数: 0
- 爬虫原理:请求网站并提取数据的自动化程序
- 通用爬虫:搜索引擎爬虫;聚焦爬虫:获取某一垂直领域的数据或者有明确的检索需求,需要过滤掉一些无用的信息
- HTTP协议:用于从WWW服务器传输文本到本地浏览器的传送协议;HTTPS协议是加密的超文本传输协议
- HTTP主要请求方式
- GET请求:是以实体的方式得到由请求URL所指定资源的信息
- POST请求:用来向目的服务发出请求,并且带上某些信息,如果用户输入的数据包敏感数据,那么使用POST为好
- PUT请求:请求服务器存储一个资源,通常要指定存储的位置
- DELETE请求:请求服务器删除一个资源
- HEAD请求:请求获取对应的HTTP头信息
- OPTIONS请求:可以获得当前URL所支持的请求类型
- HTTP头部信息:HTTP头部信息由众多的头域组成,每个头域由一个域名,冒号和域值三部分组成;F12->Network->Doc即主要请求,其中的Headers分页即请求头,包含请求头部信息
- Request Method代表的是请求方式,HTTP/1.1表示使用HTTP1.1协议标准,200OK说明请求成功
- Host头域,指定请求资源的Intenet主机和端口号,必须表示请求URL的原始服务器或网关的位置;即网址
- User_Agent头域,里面包含发出请求的用户信息,其最终由使用的浏览器型号,版本和操作系统的信息。这个头域经常用来作为反爬虫的措施,普通爬虫不包含User_Agent
- Accept:浏览器支持的内容类型
- Accept-Encoding:浏览器支持的语言类型
- Connection:客户端和服务器的连接类型,对应的字段值有keep-alive持久性连接和close单方面管理连接
- Referer来源网址地址
- 爬虫流程
- 网页特征
- 网页都有自己唯一的URL(统一资源定位符)来进行定位
- 网页都使用HTML (超文本标记语言)来描述页面信息
- 网页都使用HTTP/HTTPS(超文本传输协议)协议来传输HTML数据
- 基本流程
- 发起请求:通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待服务器响应
- 获取响应内容:如果服务器能正常响应,会得到一个Response,Response的内容便是所要获取的页面内容,类型可能有HTML,Json字符串,二进制数据(如图片视频)等类型
- 解析内容:得到的内容可能是:
- HTML,可以用正则表达式、网页解析库进行解析
- Json,可以直接转为Json对象解析
- 二进制数据,可以做保存或者进一步的处理
- 保存数据:保存形式多样,可以存为文本,也可以保存至数据库,或者保存特定格式的文件
- 爬虫与反爬虫
- 反爬虫机制:
- 分析用户请求的Headers信息,网站中应用的最多
- 验证用户行为,在短时间内是否频繁访问网站
- 动态页面增加爬虫难度
- 应对策略
- 构造用户请求的Headers信息
- 使用代理服务器并经常切换代理服务器
- 利用工具软件,例如selenium+phantomJs
- 请求与响应
- 请求Request:浏览器发送消息给该网址所在的服务器
- 主要方式有GET和POST
- URL统一资源定位符
- 请求头部信息包括User-Agent,Host,Cookies
- 请求时能携带额外的数据,即POST
- 响应Response:服务器收到浏览器发送的消息后,能够根据浏览器发送消息的内容,做相应处理,然后把消息回传给浏览器
- 响应状态:200成功,301跳转,403forbidden禁止访问,404找不到页面,502服务器错误
- 响应头,如内容类型,内容长度,服务器信息,设置Cookie(用户行为)等
- 响应体包含最主要的请求资源的内容
- 浏览器收到服务器的Response信息后,会对信息进行相应处理,然后展示
- 数据选择和处理
- 抓取数据类型:
- 网页文本HTML文档,Json格式文本
- 图片的二进制文件
- 视频的二进制文件及其他
- 解析方式
- 直接处理
- Json解析
- 正则表达式
- BeautifulSoup
- PyQuery
- XPath
- JavaScript渲染问题
- 分析Ajax
- Selenium/WebDriver
- Splash
- PyV8/Ghost.py
- 保存数据
- 文本
- 关系型mysql和非关系型Redis数据库
- 二进制文件,如图片,视频
- *爬虫工具gooseeker,八爪鱼等
- 爬虫基本请求库Urllib:Urllib是python内置的HTTP请求库,也是python爬虫的基础库
- *Urllib.request请求模块,Urllib.Error异常处理模块,Urllib.parse解析
- response=urllib.request.urlopen(url,data,timeout)->response.read().decode('')
- 前端知识:<head>包含的<meta>内有content="charset="即网页编码属性
- url网址
- data访问网站时发送的数据包,默认null
- timeout等待时长
- decode('')解码,把字节流形式数据以网页的字符格式转化为字符串
- urllib.request.urlretrieve(url,filename='*.html')直接存储html文档
- **每次操作都会有缓存,多次爬虫必须加上清除缓存的步骤urllib.request.urlcleanup()
- 搜索引擎框中的中文会自动转化为ASCII码进行搜索,所以在构造搜索网页url时,urllib.request.quote(keyword)将搜索关键字先转化为编码
- POST数据传送
- urllib.parse.urlencode({}).encode('utf-8')HTML中post方法表单中的输入框的标签name对应想要上传值的字典;用encode()将字符串转化为相应编码格式的二进制字节流形式->urllib.request.urlopen(url,data)中的data即urllib.parse.urlencode({}).encode('utf-8')想要上传的字节流数据
- encode编码,decode解码
- **urllib高级用法:应对反爬虫设置
- 设置Headers
- urllib.request.urlopen(urllib.request.Request(url=url,headers={'User-Agent':''})).read().decode();urllib.request.Request()即设置请求细节,放入headers的User-Agent浏览器信息
- Proxy(代理)的设置
- urllib.request.install_opener(urllib.request.build_opener(urllib.request.ProxyHandler({'http':proxy_addr})))设置全局代理服务器,传入proxy_addr需要加上端口
- Timeout设置urllib.request.urlopen(url,data,timeout),设置一次请求的等待时间,超过即停止请求
- 设置Cookie:Cookie即储存在浏览器中的用户信息,可用于绕过登录等,http是无状态的协议,不保存登录信息
- import http.cookiejar
- 利用登录跳转页面url
- 写data登录信息:urllib.parse.urlencode({}).encode('utf-8')
- cjar=http.cookiejar.CookieJar()创建对象
- 创建cookie处理器和opener对象,并加载cookie设置urllib.request.install_opener(urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cjar)))
- urllib.request.urlopen(url,data)请求得到登录后的页面
- 异常处理
- import urllib.error
- try:...except urllib.error.URLError|HTTPError as e:...;捕捉到URLError|HTTPError错误
- 爬虫高级请求库Request:import requests
- 特点
- Requests是用python语言基于urllib编写的HTTP请求库
- Requests实现HTTP请求非常简单,更具有Python风格,操作更加人性化
- Requests库是第三方模块,需要额外进行安装pip install requests
- 功能
- GET和POST
- requests.get(url,headers={'User-Agent':''},cookies={},proxies={},timeout=):get请求
- requests.post(url,data={}):post请求,data传入数据为method="post"的表单中的输入框的name和对应输入值
- requests.get(url).content|text:请求的字节流|文本输出,content.decode可解码
- 响应与编码:import chardet检测字符串和文件编码
- requests.get(url).encoding=chardet.detect(requests.get(url).content)['encoding']获取当前get请求网页的编码格式,直接赋值给get请求网页文件的编码
- *requests.get(url).status_code获取当前get请求网页的响应值
- Headers设置
- requests.get(url,headers):利用headers的User-Agent浏览器信息
- Cookies设置
- 登录后界面的headers内的cookie信息
- 传入的cookies为字典,且先用for循环将cookie按;切分,以第一个等号分隔name和value
- for i in string.split(';'):name,value=i.strip().split('=',1) cookie[name]=value
- requests.get(url,cookies=)利用cookies
- 代理设置
- 上网查找代理ip->proxies={'http':'ip:port'}
- requests.get(url,proxies={})利用ip
- 超时设置
- requests.get(url,timeout=)设置请求时间;可用r.status_code查看页面请求状态
- 爬虫解析法Beautiful Soup:是一个可以从HTML或XML文件中查找提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式;效率较高上手简单;pip install bs4;解析器:pip install lxml
- *解析器BeautifulSoup(markup,"")
- python标准库:html.parser,python内置
- lxml HTML解析器:lxml
- lxml XML解析器:xml,唯一支持XML的解析器
- html5lib:html5lib,以浏览器的方式解析文档,生成HTML5格式的文档
- BS将HTML文档转换成一个树形结构,每个节点即python对象,对象可分为4类
- Tag:标签<div>,<p>
- NavigableString:字符内容操作对象,表示标签里面的内容
- BeautifulSoup:文档对象,表示的是一个文档的全部内容
- Comment:特殊类型的NavigableString,为标签内注释的内容
- 使用
- from bs4 import BeautifulSoup
- 创建BS对象:读取HTML文档或使用HTML格式字符串soup=BeautifulSoup(html,"解析器")
- 利用BS对象:
- *soup.prettify()标准缩进HTML文档输出
- 获取标签:soup.标签名;若有多个同名标签,只能获取第一个标签
- 获取属性:soup.标签名.attrs,获取属性字典;soup.标签名['属性名']
- 获取标签中间的内容:soup.标签名.string
- 如果标签中只有一个子标签,返回子标签中文本内容
- 如果标签中有多个子标签,返回None
- 遍历文档树
- 子节点
- soup.标签.contents:匹配标签的所有子节点及其内容
- soup.标签.children:匹配标签的子节点列表迭代器,for i in soup.p.children
- 父节点
- soup.标签.parent:匹配标签的父节点及其内容
- soup.标签.parents:匹配标签的父节点列表迭代器
- 兄弟节点
- soup.标签.next|previous_sibling:匹配标签的同级前|后节点;实测不输出
- soup.标签.next|previous_siblings匹配标签的同级前|后所有节点列表迭代器;最好用这个输出兄弟节点
- 搜索文档树:
- soup.find_all(''):根据标签名,属性,内容查找文档;返回列表
- soup.find_all([])多个标签
- soup.find_all(re.compile('d+'))正则表达式查找,整个标签中包含d字符
- soup.find_all(id='')关键字参数查找
- soup.find_all(text='')标签中间内容匹配,得到的也是标签的中间内容
- for i in soup.find_all('p'):print(i.find_all('a'))嵌套查找,soup.find_all()也是BS对象
- soup.find(''):返回的匹配结果的第一个元素
- soup.find_parents()|soup.find_parent():查找所有|一个父节点
- soup.find_next|previous_sibling(s)():查找后|前所有|一个兄弟节点
- soup.find_(all_)next|previous():查找后|前所有|一个节点
- css选择器:返回list;css文件即对网页各个元素进行样式设计,对网页元素的多种选择方法都能在.select('')内使用
- css语法:
- 标签名不加修饰
- 类名前加.,id名前加#
- a,p:找到所有的a和p标签
- a p:找到a标签下所有的p标签
- soup.select().get_text():获取标签中间的文本内容
- 操作
- soup.select('#id'):id查找
- soup.select('.class'):class查找
- soup.select("a[href='']"):css写法的查询
- 爬虫解析法Xpath:Xpath原本是在可扩展标记语言XML中进行数据查询的一种描述语言;对于标记语言都有非常友好的支持,如超文本标记语言HTML
- 选取节点
- nodename:选取节点的所有子节点
- /:起始为/则表示从根节点选取(且为元素的绝对路径);bookstores/book表示bookstores元素的后代的所有book元素
- //:从匹配选择的当前节点中选择文档中的节点,不考虑其位置
- .:选择当前节点
- ..:选择当前节点的父节点
- @:选择属性
- 谓语:查找某个特定的节点或者包含某个指定的值的节点,谓语被嵌在方括号中,类似索引
- /bookstores/book[1]:选取属于bookstores子元素的第一个book元素
- /bookstores/book[last()]:选取属于bookstores子元素的最后一个book元素
- /bookstores/book[position()<3]:选取属于bookstores子元素的前两个book元素
- //title[@lang]:选取所有拥有名为lang的属性的title元素
- /bookstores/book[price>35]:选取bookstores元素中的所有book元素,且其中的price元素>35
- /bookstores/book[price>35]/title:选取bookstores元素中的所有book元素,且其中的price元素>35,下面的title元素
- 选取未知节点
- *:匹配任何元素节点
- @*:匹配任何属性节点
- node():匹配任何类型节点
- 路径选取
- /bookstores/*:选取bookstores元素的所有子元素
- //*:选取文档中的所有元素
- //title[@*]:选取所有带有任何属性的title元素
- //book/title|//book/price:选取book元素的所有title和price元素
- //book|//price:选取文档中所有的title和price元素
- /bookstores/book/title|//price:选取属于bookstores元素的book元素的所有title元素和文档中所有的price元素
- *div是除法
- 操作
- from lxml import etree
- 初始化构造Xpath解析对象:html=etree.HTML(text),text即HTML文档
- 利用Xpath对象
- html.xpath('//p'):查询所有p标签
- html.xpath('//@name'):查询所有name属性的值
- html.xpath('//*[@name]'):查询所有包含name 属性的标签
- html.xpath('//*[@name="desc"]'):)查询所有包含name属性,并且name属性值为desc的标签
- for p in html.xpath('//p'):print(p.text):查询所有p标签中间的文本内容,不包含子标签
- for p2 in html.xpath('//p'):print(p2.xpath('string(.)')):查询多个p标签下的所有文本内容,包含子标签中的文本内容
- html.xpath('//div/p[3]/@name'):第三个p标签的name属性值
- 爬虫解析法正则表达式:上手难但最全面;用规则字符串来表达对字符串的一种过滤逻辑;
- 操作
- import re
- re.search(pattern,string):pattern为正则表达式'',string是被检验的字符串'';匹配到的字符和所占位置,从0开始,左闭右开
- re.findall(pattern,string):返回所有匹配正则表达式的字符串列表
- re.compile(string):返回pattern对象
- re.match(pattern,string):从string的第一个字符开始匹配,如果出错直接返回None
- re.sub(pattern,replace,string,count):string中所有匹配的字符串转化为replace,count可以指定次数
- 原子:
- 普通字符:'yue'
- 非打印字符:'\n'换行符等
- 通用字符:
- \w:匹配字母、数字、下划线;等价于'[A-Za-z0-9_]'
- \W:匹配非字母、数字、下划线;等价于 '[^A-Za-z0-9_]'
- \s:匹配任何空白字符,包括空格、制表符、换页符
- \S:匹配任何非空白字符
- \d:匹配一个数字字符
- \D:匹配一个非数字字符
- \A:匹配字符串开始
- \Z:匹配字符串结束,如果存在换行,只匹配到换行前的结束字符
- \z:匹配字符串结束
- \G:匹配最后匹配完成的位置
- \n:匹配换行符
- \t:匹配制表符
- 元字符:
- ^:匹配字符串开头
- $:匹配字符串结尾
- .:匹配除换行符(\n、\r)之外的任何单个字符,当re.DOTALL标记被指定时,可以匹配任意字符;\.匹配点自身
- []:原子集
- [^]:非原子集,不存在原子集中的字符
- *:匹配0或多个的前一个原子,元字符或原子集;贪婪模式,提取后面符合规则的所有字符
- +:匹配1或多个的前一个原子,元字符或原子集;贪婪模式
- ?:匹配0或1个的前一个原子,元字符或原子集,.*?这里的?指的是.*;非贪婪模式
- |:模式选择符,设置多个模式,匹配时,可以从中任意一个模式匹配,类似原子集
- ():模式单元符,将原子组合成一个大原子使用,用findall则只截取pattern的()内的字符串
- {n}:精确匹配n个前面表达式
- {n,m}:匹配n到m次由前面正则表达式定义的片段,贪婪模式
- 原子表(字符集):[p\wh],定义一组地位平等的原子,然后匹配的时候会取该原子集中任意一个原子进行匹配
- 实例:
- 匹配.com和.cn后缀的网址:[a-zA-Z]+://[^\s]*[.com|.cn]
- 匹配电话号码:\d{4}-\d{7}|\d{3}-\d{8}
- 匹配电子邮箱:
- <br><a href='(.*?)'>
- [a-zA-Z+-]+@[a-zA-Z-]+\.\w+([.-]\w+)*,邮箱通用
转载自blog.csdn.net/u013103305/article/details/84529972