一、Handler处理器 和 自定义Opener(引擎们)

  • opener是 urllib2.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构建好的)。

  • 但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能:

    1. 使用相关的 Handler处理器 来创建特定功能的处理器对象;
    2. 然后通过 urllib2.build_opener()方法使用这些处理器对象,创建自定义opener对象;
    3. 使用自定义的opener对象,调用open()方法发送请求。
  • 如果程序里所有的请求都使用自定义的opener,可以使用urllib2.install_opener() 将自定义的 opener 对象 定义为 全局opener,表示如果之后凡是调用urlopen,都将使用这个opener(根据自己的需求来选择)

自定义简单的opener

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib2

# 构建一个HTTPHandler处理器对象,支持处理HTTP的请求
#http_handler = urllib2.HTTPHandler()

# 不加参数时,和使用urllib2.urlopen()发送HTTP/HTTPS请求得到的结果是一样的。
# 在HTTPHandler增加参数"debuglevel=1"将会自动打开Debug log 模式,程序在执行的时候会打印收发包的报头(请求头)的信息
http_handler = urllib2.HTTPHandler(debuglevel=1)

# 调用build_opener()方法构建一个自定义的opener对象,参数是构建的处理器对象
opener = urllib2.build_opener(http_handler)

request = urllib2.Request("http://www.baidu.com/")

response = opener.open(request)

# print response.read()

ProxyHandler处理器(代理设置)

使用代理IP,这是爬虫/反爬虫的第二大招,通常也是最好用的。

很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,它会禁止这个IP的访问。

所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。

urllib2中通过ProxyHandler来设置使用代理服务器,下面代码说明如何使用自定义opener来使用代理:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib2

# 代理开关,表示是否启用代理
proxyswitch = False

# 构建一个Handler处理器对象,参数是一个字典类型,包括代理类型和代理服务器IP+PROT
# httpproxy_handler = urllib2.ProxyHandler({"http" : "124.88.67.54:80"})

# 如果代理服务器有密码
authproxy_handler = urllib2.ProxyHandler({"http" : "mr_mao_hacker:sffqry9r@114.215.104.49:16816"})

# 构建了一个没有代理的处理器对象
nullproxy_handler = urllib2.ProxyHandler({})

if proxyswitch:
    opener = urllib2.build_opener(httpproxy_handler)
else:
    opener = urllib2.build_opener(nullproxy_handler)

# 构建了一个全局的opener,之后所有的请求都可以用urlopen()方式去发送,也附带Handler的功能
urllib2.install_opener(opener)

request = urllib2.Request("http://www.baidu.com/")
response = urllib2.urlopen(request)

#print response.read().decode("gbk")
print response.read()

免费代理网站:

如果代理IP足够多,就可以像随机获取User-Agent一样,随机选择一个代理去访问网站。

HTTPPasswordMgrWithDefaultRealm()

HTTPPasswordMgrWithDefaultRealm()类将创建一个密码管理对象,用来保存 HTTP 请求相关的用户名和密码,主要应用两个场景:

  1. 验证代理授权的用户名和密码 (ProxyBasicAuthHandler())
  2. 验证Web客户端的的用户名和密码 (HTTPBasicAuthHandler())
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib2

test = "test"
password = "123456"
webserver = "192.168.21.52"

test2 = "x5456"
password2 = "5456"
webserver2 = "119.130.115.226:808"

# 构建一个密码管理对象,可以用来保存和HTTP请求相关的授权账户信息
passwordMgr1 = urllib2.HTTPPasswordMgrWithDefaultRealm()
passwordMgr2 = urllib2.HTTPPasswordMgrWithDefaultRealm()

# 添加授权账户信息,第一个参数realm如果没有指定就写None,后三个分别是站点IP,账户和密码
passwordMgr1.add_password(None, webserver, test, password)
# 代理服务器的ip:port、用户名、密码
passwordMgr2.add_password(None, webserver2, test2, password2)

# HTTPBasicAuthHandler() HTTP基础验证处理器类
httpauth_handler = urllib2.HTTPBasicAuthHandler(passwordMgr1)

# 处理代理基础验证相关的处理器类
proxyauth_handler = urllib2.ProxyBasicAuthHandler(passwordMgr2)

# 构建自定义opener,里面可以加多个参数
opener = urllib2.build_opener(httpauth_handler, proxyauth_handler)

# urllib2.install_opener(opener)    # 加上这句话,urllib2.urlopen()使用的是我们自写的opener

request = urllib2.Request("http://192.168.21.52/")

# 用加上授权验证信息
response = opener.open(request)

# 没有授权验证信息
#response = urllib2.urlopen(request)

print response.read()

Cookie的应用

Cookies在爬虫方面最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续。

cookielib库 和 HTTPCookieProcessor处理器

在Python处理Cookie,一般是通过cookielib模块和 urllib2模块的HTTPCookieProcessor处理器类一起使用。

cookielib模块:主要作用是提供用于存储cookie的对象

HTTPCookieProcessor处理器:主要作用是处理这些cookie对象,并构建handler对象。

cookielib 库

该模块主要的对象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。

  • CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。

  • FileCookieJar (filename,delayload=None,policy=None):从CookieJar派生而来,用来创建FileCookieJar实例,检索cookie信息并将cookie存储到文件中。filename是存储cookie的文件名。delayload为True时支持延迟访问访问文件,即只有在需要时才读取文件或在文件中存储数据。

  • MozillaCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与Mozilla浏览器 cookies.txt兼容的FileCookieJar实例。

  • LWPCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与libwww-perl标准的 Set-Cookie3 文件格式兼容的FileCookieJar实例。

其实大多数情况下,我们只用CookieJar(),如果需要和本地文件交互,就用 MozillaCookjar() 或 LWPCookieJar()

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib,urllib2,cookielib

# 通过CookieJar()类构建一个cookieJar()对象,用来保存cookie的值
cookie = cookielib.CookieJar()

# 通过HTTPCookieProcessor()处理器类构建一个处理器对象,用来处理cookie
# 参数就是构建的CookieJar()对象
cookie_handler = urllib2.HTTPCookieProcessor(cookie)

# 构建一个自定义的opener
opener = urllib2.build_opener(cookie_handler)

# 通过自定义opener的addheaders的参数,可以添加HTTP报头参数
opener.addheaders = [("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")]

# renren网的登录接口
url = "http://www.renren.com/PLogin.do"

# 需要登录的账户密码
data = {"email":"mr_mao_hacker@163.com", "password":"alarmchime"}

# 通过urlencode()编码转换
data = urllib.urlencode(data)

# 第一次是post请求,发送登录需要的参数,获取cookie
request = urllib2.Request(url, data = data)

# 发送第一次的post请求,生成登录后的cookie(如果登录成功的话)
response = opener.open(request)

# 获取个人主页
print response.read()

# 已经有cookie了,那还不干点别的事 ,第二次可以是get请求,这个请求将保存生成cookie一并发到web服务器,服务器会验证cookie通过
response_deng = opener.open("http://www.renren.com/410043129/profile")

# 获取登录后才能访问的页面信息
print response_deng.read()

小Tips:

两种添加报头的方法

request.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")

opener.addheaders = [("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")]

二、Re模块

实际上爬虫一共就四个主要步骤

  1. 明确目标 (要知道你准备在哪个范围或者网站去搜索)
  2. 爬 (将所有的网站的内容全部爬下来)
  3. 取 (去掉对我们没用处的数据)
  4. 处理数据(按照我们想要的方式存储和使用)

对于文本的过滤或者规则的匹配,最强大的就是正则表达式,是Python爬虫世界里必不可少的神兵利器。

什么是正则表达式

正则表达式,又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

给定一个正则表达式和另一个字符串,我们可以达到如下的目的:

  • 给定的字符串是否符合正则表达式的过滤逻辑(“匹配”);
  • 通过正则表达式,从文本字符串中获取我们想要的特定部分(“过滤”)。

python——爬虫引擎,re模块,lxml库

正则表达式匹配规则

python——爬虫引擎,re模块,lxml库

python中的re模块

pattern = re.compile(r"\d")   # r表示字符串不受\n,\d,\w等转义字符影响,u表示是unicode字符串

pattern.match(str,begin,end)	# 起始位置,终止位置(是以切片的形式顾头不顾尾)    
# 从起始位置开始往后找,返回第一个符合规则的(返回的是match对象),只匹配一次

pattern.search(str,begin,end)
# 从随机位置开始往后找,返回第一个符合规则的(返回的也是match对象),只匹配一次

pattern.findall(str,begin,end)
# 匹配全部字符串,返回列表

pattern.split(str,count)	# 切割次数
# 分割字符串

pattern.sub('替换文字',"字符串")

re.I ==> 忽略大小写    re.S ==> 全文匹配

用法

match

python——爬虫引擎,re模块,lxml库

python——爬虫引擎,re模块,lxml库

search

python——爬虫引擎,re模块,lxml库

findall

python——爬虫引擎,re模块,lxml库

python——爬虫引擎,re模块,lxml库

split

python——爬虫引擎,re模块,lxml库

sub

python——爬虫引擎,re模块,lxml库

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import urllib2,urllib,re
 5 
 6 class Spider(object):
 7     def __init__(self):
 8         self.page = 1
 9         self.switch = True
10 
11     def loadPage(self):
12         """
13         下载页面
14         :return:
15         """
16         url = "http://www.neihan8.com/article/list_5_"+str(self.page)+".html"
17         # headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
18         # request = urllib2.Request(url,headers=headers)
19         # response = urllib2.urlopen(request)
20         headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
21         request = urllib2.Request(url, headers=headers)
22         print("正在下载...")
23         response = urllib2.urlopen(request)
24         html = response.read().decode('gbk')
25         self.dealPage(html)
26 
27     def dealPage(self,html):
28         """
29         处理页面
30         :return:
31         """
32         pattern = re.compile('<div\sclass="f18 mb20">(.*?)</div>',re.S)
33         content_list = pattern.findall(html.replace("<p>","").replace("</p>","").replace("<br />","").replace("<br>","").
34                                        replace("&hellip;","").replace('&rdquo;','').replace("&ldquo;",''))
35         for i in content_list:
36             self.writePage(i)
37 
38     def writePage(self,duanzi):
39         """
40         保存段子
41         :return:
42         """
43         with open('duanzi.txt','a') as f:
44             print("正在保存...")
45             f.write(duanzi.encode('utf-8'))
46 
47     def startWork(self):
48         """
49         控制爬虫是否运行
50         :return:
51         """
52         while self.switch:
53             self.loadPage()
54             userinput = raw_input("任意键继续爬取,输入q停止爬取")
55             if userinput == 'q':
56                 self.switch = False
57                 print("谢谢使用...")
58             self.page += 1
59 
60 if __name__ == '__main__':
61     duanziSpider = Spider()
62     duanziSpider.startWork()
示例:通过re模块提取段子

相关文章:

  • 2021-07-30
  • 2022-01-12
  • 2022-12-23
  • 2021-04-11
  • 2022-12-23
  • 2021-12-21
  • 2021-12-01
  • 2022-12-23
猜你喜欢
  • 2021-04-05
  • 2022-12-23
  • 2021-10-08
  • 2021-06-09
  • 2022-01-12
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案