2017.07.23 Python網絡爬蟲之爬蟲經常使用模塊

1.涉及網絡這塊,必不可少的模塊就是urllib2了。顧名思義這個模塊主要負責打開URL和HTTP協議之類的,還有一個模塊叫urllib,但它們不是升級版的關係html

 

2.urllib2請求返回網頁前端

(1)urllib2最賤的應用就是urllib2.urlopen函數了:python

urllib2.urlopen(url[,data[,timeout[,cafile[,capath[,cadefault[,context]]]]]])web

按照官方的文檔,urllib2.urlopen能夠打開HTTP,HTTPS,FTP協議的URL,主要應用於HTTP正則表達式

(2)參數:後端

它的參數中以ca開頭的都是跟身份驗證相關,不太經常使用服務器

data參數是以post方式提交URL時使用的cookie

最經常使用的就只有URL和timeout參數:url參數是提交的網絡地址(地址全稱,前端需協議名,後端需端口,好比:http://192.168.1.1:80),timeout是超時時間設置網絡

 

(3)函數返回對象:函數

****geturl()函數返回response的url信息,經常使用於url重定向的狀況;

****info()函數返回response的基本信息

****getcode()函數返回response的狀態代碼,最多見的代碼是200服務器成功返回頁面,404請求的網頁不存在,503服務器暫時不可用

(4)編寫testUrllib2.py測試:

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

import urllib2
import time
import platform
import os
import gzip
import StringIO

def clear():
"""該函數用於清屏"""
print(u"內容較多,顯示3秒後翻頁")
time.sleep(3)
OS=platform.system()
if (OS==u'Windows'):
os.system('cls')
else:
os.system('clear')

def linkBaidu():
url='http://www.baidu.com'

try:
res=urllib2.urlopen(url,timeout=3)
response=urllib2.urlopen(url,timeout=3).read()
response=StringIO.StringIO(response)
gzipper = gzip.GzipFile(fileobj=response)
html = gzipper.read()
except urllib2.URLError:
print(u"網絡地址錯誤")
exit()

with open('./baidu.txt','w+') as fp:

fp.write(html)

print(u"獲取url信息,response.geturl()\n: %s" %res.geturl())
print(u"獲取返回碼,response.getcode()\n: %s" %res.getcode())
print(u"獲取返回信息,response.info()\n: %s" %res.info())
print(u"獲取的網頁內容已保存噹噹前目錄的baidu.txt中,請自行查看")

if __name__ == '__main__':
linkBaidu()

運行過程當中遇到寫入baidu.txt文件亂碼問題
解決方法:gzip解壓讀寫(百度確實是gzip編碼),由於http請求中,若是在request header包含」Accept-Encoding」:」gzip, deflate」,
而且web服務器端支持,返回的數據是通過壓縮的,這個好處是減小了網絡流量,由客戶端根據header,在客戶端層解壓,再解碼。
urllib2 module,獲取的http response數據是原始數據,沒有通過解壓,因此這是亂碼的根本緣由。

  

返回結果:

建立的baidu.txt文件:

噹噹前目錄下已經建立過baidu.txt文件時,程序運行會出錯,須要刪除該文件再運行

 

爬取通常網站能夠用如下代碼:

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

import urllib2
import time
import platform
import os

def clear():
"""該函數用於清屏"""
print(u"內容較多,顯示3秒後翻頁")
time.sleep(3)
OS=platform.system()
if (OS==u'Windows'):
os.system('cls')
else:
os.system('clear')

def linkBaidu():
url='http://www.hqu.edu.cn'

try:

response=urllib2.urlopen(url,timeout=3)


except urllib2.URLError:
print(u"網絡地址錯誤")
exit()

with open('./baidu.txt','w+') as fp:

fp.write(response.read())

print(u"獲取url信息,response.geturl()\n: %s" %response.geturl())
print(u"獲取返回碼,response.getcode()\n: %s" %response.getcode())
print(u"獲取返回信息,response.info()\n: %s" %response.info())
print(u"獲取的網頁內容已保存噹噹前目錄的baidu.txt中,請自行查看")

if __name__ == '__main__':
linkBaidu()

3.urllib2使用代理訪問網頁:在使用網絡爬蟲時,有的網絡拒絕了一些IP的直接訪問,這時就不得不利用代理了,至於免費的代理網絡上不少,選擇一個肯定可用的proxy

 編寫testUrllib2WithProxy.py測試代理訪問網頁:

#!/usr/bin/env python
#-*- coding: utf-8 -*-
__author__ = 'hstking hstking@hotmail.com'

import urllib2
import sys
import re

def testArgument():
'''測試輸入參數,只須要一個參數 '''
if len(sys.argv) != 2:
print(u'只須要一個參數就夠了')
tipUse()
exit()
else:
TP = TestProxy(sys.argv[1])

def tipUse():
'''顯示提示信息 '''
print(u'該程序只能輸入一個參數,這個參數必須是一個可用的proxy')
print(u'usage: python testUrllib2WithProxy.py http://1.2.3.4:5')
print(u'usage: python testUrllib2WithProxy.py https://1.2.3.4:5')


class TestProxy(object):
'''這個類的做用是測試proxy是否有效 '''
def __init__(self,proxy):
self.proxy = proxy
self.checkProxyFormat(self.proxy)
self.url = 'http://www.baidu.com'
self.timeout = 5
self.flagWord = '百度' #在網頁返回的數據中查找這個關鍵詞
self.useProxy(self.proxy)

def checkProxyFormat(self,proxy):
try:
proxyMatch = re.compile('http[s]?://[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}:[\d]{1,5}$')
re.search(proxyMatch,proxy).group()
except AttributeError:
tipUse()
exit()
flag = 1
proxy = proxy.replace('//','')
try:
protocol = proxy.split(':')[0]
ip = proxy.split(':')[1]
port = proxy.split(':')[2]
except IndexError:
print(u'下標出界')
tipUse()
exit()
flag = flag and len(proxy.split(':')) == 3 and len(ip.split('.')) == 4
flag = ip.split('.')[0] in map(str,xrange(1,256)) and flag
flag = ip.split('.')[1] in map(str,xrange(256)) and flag
flag = ip.split('.')[2] in map(str,xrange(256)) and flag
flag = ip.split('.')[3] in map(str,xrange(1,255)) and flag
flag = protocol in [u'http',u'https'] and flag
flag = port in map(str,range(1,65535)) and flag
'''這裏是在檢查proxy的格式 '''
if flag:
print(u'輸入的http代理服務器符合標準')
else:
tipUse()
exit()

def useProxy(self,proxy):
'''利用代理訪問百度,並查找關鍵詞 '''
protocol = proxy.split('//')[0].replace(':','')
ip = proxy.split('//')[1]
opener = urllib2.build_opener(urllib2.ProxyHandler({protocol:ip}))
urllib2.install_opener(opener)
try:
response = urllib2.urlopen(self.url,timeout = self.timeout)
except:
print(u'鏈接錯誤,退出程序')
exit()
str = response.read()
if re.search(self.flagWord,str):
print(u'已取得特徵詞,該代理可用')
else:
print(u'該代理不可用')


if __name__ == '__main__':
testArgument()

執行結果以下:

 

 代碼詳細解釋:

(1)sys.argv:

     sys.argv[]說白了就是一個從程序外部獲取參數的橋樑,這個「外部」很關鍵,因此那些試圖從代碼來講明它做用的解釋一直沒看明白。由於咱們從外部取得的參數能夠是多個,因此得到的是一個列表(list),也就是說sys.argv其實能夠看做是一個列表,因此才能用[]提取其中的元素。其第一個元素是程序自己,隨後才依次是外部給予的參數。

(2)re.compile:compile(pattern[,flags] ) 根據包含正則表達式的字符串建立模式對象。

     經過help能夠看到compile方法的介紹,返回一個pattern對象,可是卻沒有對第二個參數flags進行介紹。第二個參數flags是匹配模式,能夠使用按位或’|’表示同時生效,也能夠在正則表達式字符串中指定。Pattern對象是不能直接實例化的,只能經過compile方法獲得

 

(3)re.search(proxyMatch,proxy).group():正則表達式中,group()用來提出分組截獲的字符串,()用來分組

import re
a = "123abc456"
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)   #123abc456,返回總體
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)   #123
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)   #abc
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)   #456

1. 正則表達式中的三組括號把匹配結果分紅三組

  •  group() 同group(0)就是匹配正則表達式總體結果
  •  group(1) 列出第一個括號匹配部分,group(2) 列出第二個括號匹配部分,group(3) 列出第三個括號匹配部分。

2. 沒有匹配成功的,re.search()返回None

 

(4)urllib2.build_opener:urllib2.urlopen()函數不支持驗證、cookie或者其它HTTP高級功能。要支持這些功能,必須使用build_opener()函數建立自定義Opener對象

參數handler是Handler實例,經常使用的有HTTPBasicAuthHandler、HTTPCookieProcessor、ProxyHandler等。

build_opener ()返回的對象具備open()方法,與urlopen()函數的功能相同。

若是要修改http報頭,能夠用:

install_opener(opener):安裝不一樣的opener對象做爲urlopen()使用的全局opener。

代理(ProxyHandler):ProxyHandler(proxies)參數proxies是一個字典,將協議名稱(http,ftp)等映射到相應代理服務器的URL,本程序中:urllib2.ProxyHandler({protocol:ip})

密碼驗證(HTTPBasicAuthHandler):HTTPBasicAuthHandler()處理程序可用add_password()來設置密碼。

realm是與驗證相關聯的名稱或描述信息,取決於遠程服務器。uri是基URL。user和passwd分別指定用戶名和密碼。

相關文章
相關標籤/搜索