前一篇文章,我们使用re模块来匹配了一个长的字符串其中的部分内容。下面我们接着来作匹配“1305101765@qq.com advantage 314159265358 1892673 3.14 little Girl try_your_best 56 123456789@163.com python3”
我们的目标是匹配‘56’,其中\d表示匹配数字,{2}表示匹配次数为两次,{M,N},M,N均为非负整数,M<=N,表示匹配M-N次。在匹配规则前面加个r的意思是表示原生字符串。
实际上我们在使用正则表达式的时候,通常先将其编译成pattern对象,使用re.compile()方法来进行编译。下面我们来匹配IP地址如:192.168.1.1。
1 import re 2 3 str=‘192.168.1.1‘ 4 5 re.search(r‘(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])‘,str)
可以看出来,正则使用起来并不简单。在上面的规则中,我们是用了三个子组,如果我们在网页上用findall匹配所有IP,它会把结果给分类了,变成(‘192’,‘168’,‘1’,‘1’)。显然这不是我们想要的。这时候,我们需要用(?:...)来表示非捕获组,即该子组匹配的字符串无法从后面获取。
有了之前的基础,我尝试着写下了如下的代码,从西刺代理网站上爬取IP地址,并用代理访问网站验证其是否可用。当中用到了python的异常处理机制。虽然代码不成熟,但还是分享出来,慢慢改进。
1 import urllib.request 2 import re 3 4 5 url="http://www.xicidaili.com/" 6 useful_ip=[] 7 def loadPage(url): 8 headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"} 9 response=urllib.request.Request(url,headers=headers) 10 html=urllib.request.urlopen(response).read().decode("utf-8") 11 return html 12 13 def getProxy(): 14 html=loadPage(url) 15 pattern=re.compile(r‘(<td>\d+</td>)‘) 16 duankou=pattern.findall(html) 17 pattern=re.compile(r‘(?:(?:[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}(?:[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])‘) 18 content_list=pattern.findall(html) 19 list_num=[] 20 for num in duankou: 21 list_num.append(num[4:-5]) 22 for i in range(len(list_num)): 23 ip=content_list[i]+ ":"+list_num[i] 24 while True: 25 proxy_support=urllib.request.ProxyHandler({‘http‘:ip}) 26 opener=urllib.request.build_opener(proxy_support) 27 opener.add_handler=[("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36")] 28 urllib.request.install_opener(opener) 29 try: 30 print("正在尝试使用 %s 访问..." % ip) 31 ip_filter="http://www.whatsmyip.org/" 32 ip_response=urllib.request.urlopen(ip_filter) 33 except urllib.error.URLError: 34 print("访问出错,这个IP不能用啦") 35 break 36 else: 37 print("访问成功!") 38 print("可用IP为: %s " % ip) 39 useful_ip.append(ip) 40 if input("继续爬取?")=="N": 41 print("有效IP如下:") 42 for key in useful_ip: 43 print(key) 44 exit() 45 else: 46 break 47 48 if __name__=="__main__": 49 getProxy()
在处理IP地址对应的端口号时,我用的一个非常笨的方法。实际上有更好的办法解决,大家也可以想一想。在上面这段代码中,使用urllib访问网站、Handler处理器自定义opener、python异常处理、正则匹配ip等一系列的知识点。任何知识,用多了才会熟练。
可以看到它运行成功,并且找到一个可用IP后会问你是否继续爬取。当然,我们可以手动构建一个IPPOOL即IP池,自定义一个函数,把可以用的IP写入一个文件保存起来,这里就不作赘述了。在github上有成熟的ip池代码,大家可以下载下来阅读,这里只是把前面讲的一些用法做一个简单的试验,因此并没有把这段代码完善。