爬虫基础

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,封账号,高频验证的网站的大规模数据采集

原文地址:https://www.cnblogs.com/suncunxu/p/10758987.html