如果要进行客户端与服务器端之间的消息传递,我们可以使用HTTP协议请求进行。
GET请求实例分析:
比如在百度上查询一个关键词,输入“love”,会观察到URL的变化:https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=love&rsv_pq=8d9d300800006e7e&rsv_t=9897ZRevPAHfRbSBtLI4jAbDCKE6aHajYVciCVNunovZTBN4urnIbdq5%2FKs&rqlang=cn&rsv_enter=1&rsv_sug3=5&rsv_sug1=4&rsv_sug7=101&rsv_sug2=0&inputT=1235&rsv_sug4=1485&rsv_sug=1
可以发现,查询信息是通过URL传递的,这里就是采用的HTTP请求中的GET方法。我们将网址提取出来分析:ie=utf-8代表编码信息,而字段wd=love就是我们要查询的信息,假如我们简化一下该网址:https://www.baidu.com/s?wd=love,此时只包含对应的wd字段,将该网址复制到浏览器刷新,同样也可以得到关键词为love的搜索结果。
根据这个规律,我们就可以通过构造GET请求,用爬虫实现在百度上自动查询某个关键词。
import urllib.request
keyword = "love"
#这里要注意,去掉https后面的s
url = "http://www.baidu.com/s?wd=" + keyword
req = urllib.request.Request(url)
data = urllib.request.urlopen(req).read()
#将爬取到的网页内容存储到1.html文件中
file = open("E://1.html","wb")
file.write(data)
file.close()
代码分析:
首先将查询的关键词赋给keyword变量,然后按照之前分析的URL格式,构造出对应的url变量,再通过urllib.request.Request()构建一个Request对象,并赋给req,通过urlopen打开对应的Request对象。此时网址中包含了GET请求信息,所以会以GET请求的方式获取该页面,随后读取页面的内容赋给data,并写入1.html文件中。
注:若关键词为中文,则应在构造url之前,先将关键词部分进行编码,编码之后再构造对应的url:
real_key = urllib.request.quote(keyword)
url = "http://www.baidu.com/s?wd=" + real_key
POST请求实例分析:
我们在进行注册、登录等操作的时候,基本上都会遇到POST请求。由于登录要用到Cookie的知识,所以关于如何登录这一块的内容,放在下次讲解Cookie时详细介绍,这里了解一下爬虫怎样实现POST数据的传递:
具体代码到学习Cookie时一起讲解。
有时用同一个IP去爬取一个网站上的网页,久了之后会被该网站服务器屏蔽。如果我们爬取别人网站的时候,在对方服务器上显示的是别人的IP地址,即使对方将显示出来的IP地址屏蔽了也无关紧要,因为我们可以换另一个IP地址继续爬取。
使用代理服务器就能很好地解决这个问题。我们可以在互联网上搜索对应的代理服务器地址,比如:http://www.xicidaili.com/:
可以看到,这里会更新很多代理IP地址,我们尽量找验证时间短的,成功的概率会更大。此时我们选择第一个代理IP地址:183.154.52.56,端口号是45186,完整的格式为:网址:端口号。即,183.154.52.56:45186。
用了代理IP地址后,我们就可以进行相应程序的编写了:
import urllib.request
def use_proxy(proxy_addr,url):
proxy = urllib.request.ProxyHandler({"http":proxy_addr})
opener = urllib.request.build_opener(proxy,urllib.request.HTTPHandler)
urllib.request.install_opener(opener)
data = urllib.request.urlopen(url).read().decode("utf-8")
return data
proxy_addr = "183.154.52.56:45186"
data = use_proxy(proxy_addr,"http://www.baidu.com")
print(len(data))
首先定义了一个函数,该函数用于实现代理服务器来爬取某个页面。函数中有两个形参,第一个形参为代理服务器的地址,第二个形参代表要爬取的网页的地址。
然后使用ProxyHandler来设置服务器信息,格式为:{"http":代理服务器地址},接着创建一个opener对象,第一个参数为代理信息,第二个参数为urllib.request.HTTPHandle类。
一般情况下我们访问一个URL需要使用一个opener,即urlopen(),但基本的urlopen()函数不支持验证、Cookie或其他HTTP高级功能。要支持这些功能,必须使用build_opener()函数来创建自己的自定义open对象。
为了方便,可以使用urllib.request.install_opener()创建全局默认的opener对象,那么在使用urlopen()时也会使用我们安装的opener对象,所以下面才可以直接使用urllib.request.urlopen()打开对应网址爬取网页并读取。
程序执行的结果如下:
什么是正则表达式
简单来说,正则表达式就是描述字符串排列的一套规则,主要用于字符串的匹配,在Python中,我们一般会使用re模块来实现正则表达式的功能。
接下来介绍一下正则表达式的基础知识:
1.原子
原子是正则表达式中最基本的组成单位,常见的原子有以下几类:
接下来分别讲解:
(1)普通字符作为原子
import re
pattern = "lmn"
string = "http://ilovelmn.com"
result = re.search(pattern,string)
print(result)
其中,pattern为普通字符组成的字符串,将其看作正则表达式,然后使用re模块中的search()函数,从string中去匹配对应的正则表达式,此时执行结果如下,可以看到成功匹配到了对应的"lmn",因为在string中包含对应符合正则表达式规则的字符串。
(2)非打印字符作为原子
非打印字符指的是一些在字符串中用于格式控制的符号,比如换行符等。例如可以通过以下程序来实现对换行符的匹配。
import re
pattern = "\n"
string = '''http://ilovelmn.com
iloveyou'''
result = re.search(pattern,string)
print(result)
若无法成功匹配,则输出None。
(3)通用字符作为原子
通用字符,即一个原子可以匹配一类字符。
\w:匹配任意一个字母、数字或下划线。
\W:匹配除字母、数字和下划线以外的任意一个字符。
\d:匹配任意一个十进制数。
\D:匹配除十进制数以外的任意一个其它字符。
\s:匹配任意一个空白字符。
\S匹配除空白字符以外的任意一个其它字符。
import re
pattern = "\w\dloveyou\w"
string = "http://ilovelmn86loveyou6com"
result = re.search(pattern,string)
print(result)
程序结果显示匹配成功。
(4)原子表
使用原子表,可以定义一组地位平等的原子,然后匹配的时候会取该原子表中的任意一个原子进行匹配,比如[xyz]就是一个原子表,这个院子表中定义了3个原子,这3个原子地位平等。类似的,[^]代表的是除了中括号里面的原子均可以匹配。程序略。
2.元字符
元字符就是正则表达式中具有一些特殊含义的字符,比如重复n次前面的字符等。
.:匹配除换行符以外的任意字符。
^:匹配字符串的开始位置。
$:匹配字符串的结束位置。
*:匹配0次、1次或多次前面的原子。
?:匹配0次或1次前面的原子。
+:匹配1次或多次前面的原子。
{n}:前面的原子恰好出现n次。
{n,}:前面的原子至少出现n次。只要满足格式,就会在源字符中尽可能多地匹配字符。
{n,m}:前面的原子至少出现n次,至多出现m次。
|:模式选择符。
():模式单元符。
具体来说,以上元字符可以分为:任意匹配元字符、边界限制元字符、限定符、模式选择符合模式单元等。
3.模式修正
模式修正符,可以在不改变正则表达式的情况下,通过模式修正符改变正则表达式的含义,从而实现一些匹配结果的调整。
I:匹配时忽略大小写。
M:多行匹配。
L:做本地化识别匹配。
U:根据Unicode字符及解析字符。
S:让 . 去匹配包括换行符,即用了该模式修正后," . "匹配就可以匹配任意字符了。
import re
pattern = "love"
string = "ILoveYou"
result = re.search(pattern,string,re.I)
print(result)
贪婪模式与懒惰模式
总的来说,贪婪模式的核心点就是尽可能多地匹配,而懒惰模式的核心点就是尽可能少地匹配。
通常情况下,我们想在某些字符间匹配任意字符,像" p.*y "这样写默认是使用贪婪模式的,如果要转化为懒惰模式,需要在对应的" .* "后面加上" ? ",则转化为懒惰模式。
正则表达式的常见函数
1.re.match()函数
如果想要从源字符串的起始位置匹配一个模式,我们可以使用re.match()函数,该函数的使用格式为:re.match(pattern,string,flag),第一个参数代表对应的正则表达式,第二个参数代表对应的源字符,第三个参数是可选参数,可以放模式修正符等信息。
import re
pattern = ".love"
string = "iloveyoupython"
result = re.match(pattern,string).span()
print(result)
其中的span()可以过滤掉一些信息,只留下匹配成功的结果在源字符串中的位置。
2.re.search()函数
使用该函数进行匹配,会扫描整个字符串并进行相应的匹配。该函数与re.match()函数最大的不同是,后者从源字符串的开头进行匹配,而前者会在全文中进行检索并匹配。
3.全局匹配函数
如果源字符串中有多个结果符合模式,我们如何将符合模式的内容全部都匹配出来呢?
思路如下:
import re
pattern = re.compile(".love.")
string = "iloveyouthislovedabendan"
result = pattern.findall(string)
print(result)
4.re.sub()函数
如果想根据正则表达式来实现替换某些字符串的功能,可以使用re.sub()函数实现,格式:re.sub(pattern,rep,string,max)。第一个参数为对应的正则表达式,第二个参数为替换成的字符串,第三个参数为源字符串,第四个参数为可选项,代表最多替换的次数,如果忽略不写,则会将符合模式的结果全部替换。
import re
pattern = "python."
string = "iloveyouthispythonlovepythondabendan"
#全部替换
result1 = re.sub(pattern,"HZC",string)
#最多替换一次
result2 = re.sub(pattern,"HZC",string,1)
print(result1)
print(result2)