HTTPS是以安全为目标的HTTP通道,安全基础是SSL,传输的内容全部是由SSL加密的,某些网站使用HTTPS协议,但仍然会被浏览器提示不安全,是因为有些网站的CA证书不是被CA机构信任的,如果要爬取这样的站点,就要设置忽略证书的选项
请求头:
Accept:请求报头域,用于指定客户端可接受那些类型的信息
Accept-Language:指定客户端可接受的语言类型.
Accept-Encoding:指定客户端可接受的内容编码
Host:用于指定请求资源的主机IP和端口号,其内容为请求URL的原始服务器或网关的位置
Cookie:是网站用于辨别用户进行会话跟踪而存储在用户本地的数据
Referer:此内容用来标识这个请求是从哪个页面发过来的
User-Agent:简称UA,是一个特殊的字符串头,可以使服务器识别客户使用的操作系统及版本,浏览器及其版本信息,爬虫需要加上此信息
Content-Type:也叫互联网媒体类型,或者MIME类型,在HTTP协议消息头中,它用来表示具体请求的媒体类型信息
响应头:
Date:标识响应产生的时间
Last-Modified:指定资源的最后修改时间
Content-Encoding:指定响应内容的编码
Server:包含服务器的信息,比如名称,版本号等
Content-Type:文档类型,指定返回的数据类型是什么
Set-Cookie:设置Cookies,响应头中的Set-Cookie告诉浏览器需要将此内容放在Cookies中下次请求携带Cookies请求.
Expires:指定响应的过期时间,可以使代理服务器或浏览器将加载的内容更新到缓存中
HTML定义了网页的内容和结构,CSS描述了网页的布局,JavaScript定义了网页的行为
有时候我们在使用urllib或requests抓取网页时,得到的源代码实际和浏览器中看到的不一样,这是因为网页越来越多的采用Ajax,前端模块化工具来构建,整个网页可能都是由JavaScript渲染出来的
HTTP的无状态是指HTTP协议对事物处理是没有记忆能力的,会话和Cookies用于保持HTTP连接状态的技术.会话在服务器保存用户的会话信息,Cookies在客户端保持信息,服务器通过识别Cookies鉴定那个用户
文件上传:
import requests
files={'file':open('favicon.ico','rb')}
r = requests.post('http:wwwcsb.com',files=files)
会话维持:
在requests中,如果直接利用get()和post()等方法的确可以做到模拟网页的请求,但是这实际上相当于两个不同的会话,类似于使用两个浏览器打开了不同的页面
利用Session,可以做到模拟同一个会话而不担心Cookies的问题,通常用于模拟登陆成功之后再进行下一步的操作
SSL证书验证:
当发送HTTP请求时,他会检查SSL证书,通过使用verify参数控制是否检查此证书,默认值为True,
import requests
response=requests.get('https://www.12306.cn',verify=False)
这时请求成功会发现警告,建议我们给他指定证书,我们可以通过设置忽略警告的方式来屏蔽这个警告
from requests.packages import urllib3
urllib3.disable_warning()....
代理设置:
设置代理使用proxies参数
proxies={"http":"http://10.10.1.10:3128","https":"http://10.10.1.10:1080"}
requests.get("https://www.taobao.com",proxies=proxies)
若代理需要使用HTTP Basic Auth,可以使用类似http://user:password@host:port这样的语法设置代理
proxies={"http":"http://user:password@10.10.1.10:3128/"}
除了基本的HTTP代理外,requests还支持SOCKS协议的代理
需要安装socks库: pip3 install 'requests[socks]'
proxies={'http:'socks5://user:password@host:port','https':'socks5://user:password@host:port'}
超时设置:
设置超时时间需要使用timeout参数,
r = requests.get("https://www.taobao.com",timeout=1)
将超时时间设置为1秒.若1秒内没有响应就将抛出异常,实际上,请求分为两个阶段,连接与读取,timeout作用连接和读取的时间总和永久登台设置为None,默认为None
身份认证
访问网站遇到认证页面可以使用requests自带的身份认证功能
from requests.auth import HTTPBasicAuth
r = requests.get('http://loaclhost:5000',auth=HTTPBasicAuth('username','password'))
requests提供了更简单的写法直接传入一个元组,就会默认使用HTTPBasicAuth这个类来认证
r = requests.get('http://localhost:5000',auth=('username','password'))
Prepared Request
将请求表示为数据结构,各个参数可以通过Request对象表示
from requests import Request,Sesson
url = 'http://httpin.org/post'
data={'name':'germey'}
hedaders={'User-Agent':'Mozilla;Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/53.0.2785.116 Safari/537.36'}
s =Session()
req = Request('POST',url,data=data,headers=headers)
preppd=s.prepare_request(req)
r = s.send(prepped) ------r.text
这里引入了Request,然后用url,data和headers参数构造了一个Request对象,这是需要再调用Session的prepare_request()方法将其转换为一个Prepared Request对象,然后再调用send()方法发送即可,可以达到同样的post请求,
有了Request对象,就可以将请求当做独立的对象来看待,这样在进行队列调度时十分方便,后面将用它来构造一个Request队列
正则表达式:
match()
第一个参数传入正则表达式,第二个参数传入了要匹配的字符串
result = re.match('^sd+',content)
group方法可以输出匹配的内容,span()方法可以输出在原字符串的范围
贪婪匹配匹配尽可能多的字符非贪婪匹配匹配尽可能少的字符
re.I:使匹配对大小写不感兴趣
re.S:使.匹配包括换行在内的所有字符
可以使用转义匹配匹配非正常字符串
match()方法从头开始匹配,不符合就匹配失败
search()
返回第一个匹配成功的结果
findall()
查找所有符合的结果,返回的是字符串
sub():
修改文本,cotent = re.sub('\d+','',content),
第一个参数为匹配的正则表达式,第二个参数为替换成的字符串,第三个参数为原字符串
compile():
可以将正则表达式编译成正则表达式对象,以便在后面的匹配中复用
pattern = re.compile('\d+:\d+')
result = re.sub(pattern,'',content)
注意不要在Elements中直接查看源码,那里的源码可能经过JavaSCript操作而与原始请求不同,需要从Network选项卡部分查看原始请求得到的源码
xpath解析器
/ 从当前节点选取直接子节点
//从当前节点选取子孙节点
.选取当前节点
..选取当前节点的父节点 parent::*同样是父节点
@选取属性
result = html.xpath('//li[@class='sb']')进行属性匹配
text()方法用于获取文本
/text()获取文本,//text()获取子孙节点所有文本
属性获取:result=html.xpaht('//li/a/@href')返回值为列表类型
ancestor::*可以获取所有祖先节点
attribute::*可以获取所有属性值
child::* 可以获取所有直接子节点
descendant::*获取所有子孙节点
following::*获取所有当前节点之后的节点,
following-sibling::*获取当前节点之后的所有同级节点
Beautiful Soup
Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为UTF-8编码
基本用法:
soup = BeautifulSoup(html,'lxml')
soup.title.string
其中html是一个HTML字符串,第二个参数为解析器类型,
prettify()可以将要解析的字符串以标准的缩进格式输出,soup.title.string获取title节点的文本内容***且只能获取到第一个节点
提取节点信息
string属性用于获取文本的值,
name属性获取节点的名称
attrs可以获取所有属性,返回值为字典,
attrs['name']用于获取name属性
contents属性得到的结果是直接子节点的列表
child属性返回的结果是生成器类型,
descendants属性得到所有子孙节点返回结果是生成器
parent获取某个元素的父节点
parents得到所有该节点的祖先节点,返回结果是生成器类型
next_sibling和previous_sibling分别获取节点的下一个和上一个兄弟元素
next_siblings和previous_siblings分别返回后面的和前面的所有兄弟节点
Pyquery
from pyquery import PyQuery as pq
doc=pq(html)
print(doc('li'))
也可以使用doc = pq(url='https://www.baidu.com')
这样PyQuery对象会首先请求这个URL,然后用得到的HTML内容完成初始化
也可以使用doc=pq(filename='sb.html')将读取本地的文件内容,然后以字符串的形式传递给PyQuery类来初始化
Ajax数据爬取
渲染网页:比如通过document.getElementById('sb').innerHTML=xmlhttp.responseText,就可以更换数据
Ajax其实有其特殊的请求类型,他叫做xhr,就是Ajax请求,
模拟Ajax请求需要在请求头中加入参数'X-Requestes-With':'XMLHttpRequest'
若爬取一个网站,返回的html文本并没有页面中渲染的数据,需要查看ajax请求,查看返回值的data数据是否包含,
动态渲染页面爬取:
我们可以直接使用模拟浏览器运行的方式来实现可见即可爬
Selenium:
访问页面:
from selenium import webdriver
browser=webdriver.Chrome()
browser.get('https://www.taobao.com')
print(broweser.page_source)
节点交互:
Selenium可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作,常见的有:
输入文字时:send_keys(),清空文字时:clear(),点击按钮时用click()方法:示例如下:
input= browser.find_element_by_id('sb')
input.send_keys('sb')
input.clear()
button=browser.find_element_by_class_name('btn')
button.click()
切换到具体框架switch_to.frame('name')
执行JavaScript:
可以通过使用execute_script()方法实现
browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
browser.execute_script('alert('To Bottom!')')
获取属性值:(标签为logo):logo.get_attribute('class')参数为属性名,得到的就是属性值
获取文本值:logo.text
id获取节点id,location获取该节点在页面中的相对位置,tag_name属性可以获取标签名称,size属性可以获取节点的大小,也就是宽高
延时等待
隐士等待:当使用隐士等待执行测试时,如果Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常,
browser = webdriver.Chrome()
browser.implicitly_wait(10)
显示等待
指定要查找的节点,制定一个最长等待时间,若果规定时间内加载出来了这个节点,就返回,若没有则抛出异常示例如下:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome()
browser.get('http://www.taobao.com/')
wait=WebDriverWait(browser,10)
input=wait.until(EC.presence_of_element_located((By.ID,'sb')))
button=wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.btn-search')))
前进和后退
使用back()方法后退,使用forward()方法前进
Cookies:
使用Selenium,可以方便的对Cookies进行操作,例如获取删除,添加Cookies等,示例如下:
browser=webdriver.Chrome()
browser.get('http://www.zhihu.com/explore')
browser.get_cookies()
browser.add_cookie({'name':'sb'})
browser.delete_all_cookies()
选项卡管理:
browser = webdriver.Chrome()
browser.get('http://www.baidu.com')
browser.execute_script('window.open()')
print(browser.window_handles)
browser.witch_to_window(browser.window_handles[1])
图形验证码的识别:
识别最简单的图形验证码:
import tesserocr
from PIL import Image
image = Image.open('code.jpg')
result = tesserocr.image_to_text(image)
print(result)
在这里我们新建了一个Image对象,调用了tesserocr的image_to_text()方法,传入该Image对象,即可完成识别,
另外还有一种更简单的方法,这个方法可以直接将图片文件转为字符串
print(tesserocr.file_to_text('image.jpg'))但是识别效果不如上一种
在遇到验证码内有多余线条干扰了图片的识别,对于这种情况需要做额外的处理,如转灰度,二值化等操作
可以利用Image对象的convert()方法参数传入L,即可将图像转化为灰度图像,代码如下,
image = image.convert('L')
image.show()
传入1即可将图片先转为灰度图像,然后再指定二值化阈值,代码如下:
image= image.convert('1')
image.show()
还可以指定二值化的阈值,上面采用的方法默认是阈值127,我们不能直接转化原图,要将原图先转为灰度图像,然后在指定二值化阈值,代码如下:
image= image.convert('L')
threshold = 80
table =[]
for i in range(256):
if i <threshold:
table.append(0)
else:
table.append(1)
image = image.point(table,'1')
image.show()
在这里变量threshold代表二值化阈值,阈值设定为80,
这时重新识别验证码:result = terrerocr.image_to_text(image)
针对一些有干扰的图片,我们做一些灰度和二值化处理,会提高图片的识别率
代理池:
requests代理设置:我们只需要传入proxies参数即可
proxy = '127.0.0.1:9743'
proxies={'http':'http://'+proxy,'https':'https://'+proxy',}
try:
response = requests.get('http://httpbin.org/get',proxies=proxies)
print(response.text)
如果代理需要认证,需要在代理的前面加上用户名密码即可
proxy = 'username:password@127.0.0.1:9743'
如果需要使用SOCKS5代理,则可以使用如下方式来设置:
proxies={'http':'socks5://'+proxy,'https':'socks5://'+proxy}
在这里需要额外安装一个模块,这个模块是requests[socks]
Selenium设置代理
示例如下
from selenium import webdriver
proxy = '127.0.0.1:9743'
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--proxy-server=http://'+proxy)
browser=webdriver.Chrome(chrome_options=chrome_options)
认证代理实在麻烦不要用
Pyspider
如果要快速实现一个页面的抓取,推荐使用pyspider,开发更加便捷,如快速抓取某个普通新闻网站的新闻内容,如果要应对反爬程度很强,超大规模的抓取,推荐使用Scrapy,如抓取IP,封账号,高频验证的网站的大规模数据采集