python爬蟲入門(二)Opener和Requests


Handler和Opener

Handler處理器和自定義Opener

opener是urllib2.OpenerDirector的實例,我們之前一直在使用urlopen,它是一個特殊的opener(也就是我們構建好的)。

但是urlopen()方法不支持代理、cookie等其他的HTTP/GTTPS高級功能。所有要支持這些功能:

  1.使用相關的Handler處理器來創建特定功能的處理器對象;

  2.然后通過urllib2.build_opener()方法使用這些處理器對象,創建自定義opener對象;

  3.使用自定義的opener對象,調用open()方法發送請求。

如果程序里所有的請求都使用自定義的opener,可以使用urllib2.install_open()將自定義的opener對象定義為全局opener,表示如果之后凡是調用urlopen,都將使用這個opener(根據自己的需求來選擇)

簡單的自定義opener()

# _*_ coding:utf-8 _*_
import urllib2

# 構建一個HTTPHandler處理器對象,支持處理HTTP的請求
http_handler = urllib2.HTTPHandler()
# 調用build_opener()方法構建一個自定義的opener對象,參數是構建的處理器對象
opener = urllib2.build_opener(http_handler)

request = urllib2.Request('http://www.baidu.com/s')
# 調用自定義opener對象的open()方法,發送request請求
response = opener.open(request)

print response.read()

debug log模式

可以在HTTPHandler里面加參數(debuglevel=1)打開

# _*_ coding:utf-8 _*_
import urllib2

# 構建一個HTTPHandler處理器對象,支持處理HTTP的請求
# http_handler = urllib2.HTTPHandler()
# 主要用於調試用
http_handler = urllib2.HTTPHandler(debuglevel=1)
# 調用build_opener()方法構建一個自定義的opener對象,參數是構建的處理器對象
opener = urllib2.build_opener(http_handler)

request = urllib2.Request('http://www.baidu.com/s')
response = opener.open(request)
# print response.read()

ProxyHandler處理器(代理設置)

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

很多網站會檢測某一段時間某個IP的訪問次數(通過流量統計,系統日志等),如果訪問次數多的不像正常人,它會禁止這個IP的訪問。

所以我們可以設置一些代理服務器,每隔一段時間換一個代理,就算IP被禁止,依然可以換個IP繼續爬取。

urllib2中通過ProxyHandler來設置使用代理服務器,使用自定義opener來使用代理:

免費代理網站:http://www.xicidaili.com/;https://www.kuaidaili.com/free/inha/

 

# _*_ coding:utf-8 _*_
import urllib2

# 構建一個Handler處理器對象,參數是一個字典類型,包括代理類型和代理服務器IP+Port
httpproxy_handler = urllib2.ProxyHandler({'http':'118.114.77.47:8080'})
#使用代理
opener = urllib2.build_opener(httpproxy_handler)
request = urllib2.Request('http://www.baidu.com/s')

#1 如果這么寫,只有使用opener.open()方法發送請求才使用自定義的代理,而urlopen()則不使用自定義代理。
response = opener.open(request)

#12如果這么寫,就是將opener應用到全局,之后所有的,不管是opener.open()還是urlopen() 發送請求,都將使用自定義代理。
#urllib2.install_opener(opener)
#response = urllib2.urlopen(request)

print response.read()

 

但是,這些免費開放代理一般會有很多人都在使用,而且代理有壽命短,速度慢,匿名度不高,HTTP/HTTPS支持不穩定等缺點(免費沒好貨),所以,專業爬蟲工程師會使用高品質的私密代理

 私密代理

(代理服務器都有用戶名和密碼)必須先授權才能用

# _*_ coding:utf-8 _*_
import urllib2

#必須輸入用戶名密碼,ip和port
authproxy_handler = urllib2.ProxyHandler({'http':'username:pwd@ip:port})
opener = urllib2.build_opener(authproxy_handler)
request = urllib2.Request('http://www.baidu.com/s')
response = opener.open(request)
print response.read()

為了安全一般把私密代理ip用戶名密碼保存到系統環境變量里面,再讀出來

# _*_ coding:utf-8 _*_
import urllib2
import os 

# 從環境變量里面取到用戶名和密碼
proxyuser = os.environ.get('proxuser')   
proxypasswd = os.environ.get('proxpasswd')
#必須輸入用戶名密碼,ip和port
authproxy_handler = urllib2.ProxyHandler({'http':proxyuser+':'+proxypasswd+'@ip:port'})
opener = urllib2.build_opener(authproxy_handler)
request = urllib2.Request('http://www.baidu.com/s')
response = opener.open(request)
print response.read()

 Cookielib庫和HTTPCookieProcess處理器

 Cookie :是指某些網站服務器為了辨別用戶身份和進行Session跟蹤,而儲存在用戶瀏覽器上的文本文件,Cookie可以保持登錄信息到用戶下次與服務器的會話。

cookielib模塊:主要作用是提供用於存儲cookie的對象

HTTPCookieProcessor處理器:主要作用是處理這些cookie對象,並構建handler對象。

cookie庫

該模塊主要的對象有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()

下面通過實例登錄人人網,學習cookieJar()用法

登錄人人網

# _*_ coding:utf-8 _*_
import urllib2
import urllib
import 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 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36')]
#renren網的登錄接口
url = 'http://www.renren.com/PLogin.do'
#需要登錄的賬號密碼
data = {'email':'15********','password':'py********'}
# 通過urlencode()編碼轉換
data = urllib.urlencode(data)
# 第一次是POST請求,發送登錄需要的參數,獲取cookie
request = urllib2.Request(url,data = data)
response = opener.open(request)
print response.read()

有了cookie之后,可以直接爬取其它頁面

# _*_ coding:utf-8 _*_
import urllib2
import urllib
import 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 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36')]
#renren網的登錄接口
url = 'http://www.renren.com/PLogin.do'
#需要登錄的賬號密碼
data = {'email':'15********','password':'python********'}
# 通過urlencode()編碼轉換
data = urllib.urlencode(data)

request = urllib2.Request(url,data = data)
response = opener.open(request)
# print response.read()

# 可以直接爬取登錄后的其它頁面了
response_other = opener.open('http://friend.renren.com/managefriends')
print response_other.read()

Requests模塊

安裝:直接pip install requests

Requests 繼承了urllib2的所有特性。Requests支持HTTP連接保持和連接池,支持使用cookie保持會話,支持文件上傳,支持自動確定響應內容的編碼,支持國際化的 URL 和 POST 數據自動編碼。

添加headers和查詢參數

# _*_ coding:utf-8 _*_

import requests

kw = {'wd':'python'}
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}

# params 接收一個字典或者字符串的查詢參數,字典類型自動轉換為url編碼,不需要urlencode()
response = requests.get("http://www.baidu.com/s?", params = kw, headers = headers)

# 查看響應內容,response.text 返回的是Unicode格式的數據
print response.text

# 查看響應內容,response.content返回的字節流數據
print response.content

# 查看完整url地址
print response.url

# # 查看響應頭部字符編碼
print response.encoding

# 查看響應碼
print response.status_code

使用代理

# _*_ coding:utf-8 _*_

import requests

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}
# 根據協議類型,選擇不同的代理
proxies = {
  "http": "http://119.28.152.208:80",
}

response = requests.get("http://www.baidu.com/", proxies = proxies,headers=headers)
print response.text

私密代理驗證

urllib2 這里的做法比較復雜,requests只需要一步:

# _*_ coding:utf-8 _*_

import requests

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}

proxy = { "http": "name:pwd@ip:port" }

response = requests.get("http://www.baidu.com/", proxies = proxy,headers=headers)

print response.text

web客戶端驗證

import requests

auth=('test', '123456')

response = requests.get('http://192.168.xxx.xx', auth = auth)

print response.text

session

在 requests 里,session對象是一個非常常用的對象,這個對象代表一次用戶會話:從客戶端瀏覽器連接服務器開始,到客戶端瀏覽器與服務器斷開。

會話能讓我們在跨請求時候保持某些參數,比如在同一個 Session 實例發出的所有請求之間保持 cookie 。

登錄人人網

# _*_ coding:utf-8 _*_

import requests

# 1. 創建session對象,可以保存Cookie值
ssion = requests.session()

# 2. 處理 headers
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}

# 3. 需要登錄的用戶名和密碼
data = {"email":"158xxxxxxxx", "password":"pythonxxxxxxx"}

# 4. 發送附帶用戶名和密碼的請求,並獲取登錄后的Cookie值,保存在ssion里
ssion.post("http://www.renren.com/PLogin.do", data = data)

# 5. ssion包含用戶登錄后的Cookie值,可以直接訪問那些登錄后才可以訪問的頁面
response = ssion.get("http://zhibo.renren.com/news/108")

# 6. 打印響應內容
print response.text

頁面解析和數據處理

 爬蟲一共就四個主要步驟:

  1. 明確目標 (要知道你准備在哪個范圍或者網站去搜索)
  2. 爬 (將所有的網站的內容全部爬下來)
  3. 取 (去掉對我們沒用處的數據)
  4. 處理數據(按照我們想要的方式存儲和使用)

一般來講對我們而言,需要抓取的是某個網站或者某個應用的內容,提取有用的價值。內容一般分為兩部分,非結構化數據和結構化數據。

非結構化數據:先有數據,再有結構

結構化數據:先有結構,再有數據

1.非結構化的數據處理

1.文本、電話號碼、郵箱地址  

    -->正則表達式

2.HTML文件   

     -->正則表達式,XPath,CSS選擇器

2.結構化的數據處理

1.JSON文件 

    -->JSON Path

    -->轉化成python類型進行操作

2.XML文件

    -->轉化成python類型(xmltodict)

    -->XPath

    -->CSS選擇器

    -->正則表達式

正則表達式

簡單回顧下python正則表達式的一些使用方法

正則表達式測試網站:http://tool.oschina.net/regex/#

re 模塊的一般使用步驟如下:

  1. 使用 compile() 函數將正則表達式的字符串形式編譯為一個 Pattern 對象

  2. 通過 Pattern 對象提供的一系列方法對文本進行匹配查找,獲得匹配結果,一個 Match 對象。

  3. 最后使用 Match 對象提供的屬性和方法獲得信息,根據需要進行其他的操作
pattern = re.compile('\d')    #將正則表達式編譯成一個pattern規則對象

pattern.match()    #從起始位置開始往后查找,返回第一個符合規則的,只匹配一次
pattern.search()   #從任意位置開始往后查找,返回第一個符合規則的,只匹配一次
pattern.findall()  #所有的全部匹配,返回列表
pattern.finditer() #所有的全部匹配,返回的是一個迭代器
pattern.split()    #分割字符串,返回列表
pattern.sub()      #替換
re.I   #表示忽略大小寫
re.S   #表示全文匹配

1.match()

import re

pattern = re.compile('\d+')

m = pattern.match('aaa123bbb456',3,5)   #可以指定match起始和結束的位置match(string,begin,end)
print m.group()     #12

m = pattern.match('aaa123bbb456',3,6)
print m.group()     #123
import re
#匹配兩組, re.I忽略大小寫
pattern = re.compile(r"([a-z]+) ([a-z]+)",re.I)  #第一組(字母)和第二組(字母)之間以空格分開
m = pattern.match("Hello world and Python")

print m.group(0)     #Hello world    group(0)獲取所有子串
print m.group(1)     #Hello          group(1)所有子串里面的第一個子串
print m.group(2)     #world          group(2)所有子串里面的第二個子串

2.search()

import re

pattern = re.compile(r'\d+')
m = pattern.search('aaa123bbb456')
print m.group()    #123

m = pattern.search('aaa123bbb456',2,5)
print m.group()    #12

3.findall()

import re

pattern = re.compile(r'\d+')
m = pattern.findall('hello 123456 789')   #
print m    #['123456', '789']

m = pattern.findall('hello 123456 789',5,10)
print m    #['1234']

4.split()

# _*_ coding:utf-8 _*_

import re

pattern = re.compile(r'[\s\d\\\;]+')    #以空格,數字,'\',';'做分割

m = pattern.split(r'a b22b\cc;d33d   ee')

print m        #['a', 'b', 'b', 'cc', 'd', 'd', 'ee']   

5.sub()

# _*_ coding:utf-8 _*_

import re

pattern = re.compile(r'(\w+) (\w+)')
str = 'good 111,job 222'

m = pattern.sub('hello python',str)

print m    #hello python,hello python

m = pattern.sub(r"'\1':'\2'",str)

print m    #'good':'111','job':'222'
# _*_ coding:utf-8 _*_

import re

pattern = re.compile(r'\d+')
str = 'a1b22c33d4e5f678'

m = pattern.sub('*',str)    #a*b*c*d*e*f*   把數字替換成'*'
print m

內涵段子實例

 爬取貼吧所有內容,並通過正則表達式爬取出所有的段子

url變化

  • 第一頁url: http: //www.neihan8.com/article/list_5_1 .html

  • 第二頁url: http: //www.neihan8.com/article/list_5_2 .html

  • 第三頁url: http: //www.neihan8.com/article/list_5_3 .html

 

pattern = re.compile('<dd\sclass="content">(.*?)</dd>', re.S)
每個段子內容都是在 <dd class='content'>......</dd>里面,通過正則可以獲取內
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib2
import re

class Spider: def __init__(self): # 初始化起始頁位置 self.page = 1 # 爬取開關,如果為True繼續爬取 self.switch = True def loadPage(self): """ 作用:下載頁面 """ print "正在下載數據...." url = "http://www.neihan.net/index_" + str(self.page) + ".html" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'} request = urllib2.Request(url, headers = headers) response = urllib2.urlopen(request) # 獲取每頁的HTML源碼字符串 html = response.read() #print html # 創建正則表達式規則對象,匹配每頁里的段子內容,re.S 表示匹配全部字符串內容 pattern = re.compile('<dd\sclass="content">(.*?)</dd>', re.S) # 將正則匹配對象應用到html源碼字符串里,返回這個頁面里的所有段子的列表 content_list = pattern.findall(html) # 調用dealPage() 處理段子里的雜七雜八 self.dealPage(content_list) def dealPage(self, content_list): """ 處理每頁的段子 content_list : 每頁的段子列表集合 """ for item in content_list: # 將集合里的每個段子按個處理,替換掉無用數據 item = item.replace("<p>","").replace("</p>", "").replace("<br/>", "") # 處理完后調用writePage() 將每個段子寫入文件內 self.writePage(item) def writePage(self, item): """ 把每條段子逐個寫入文件里 item: 處理后的每條段子 """ # 寫入文件內 print "正在寫入數據...." with open("tieba.txt", "a") as f: f.write(item) def startWork(self): """ 控制爬蟲運行 """ # 循環執行,直到 self.switch == False while self.switch: # 用戶確定爬取的次數 self.loadPage() command = raw_input("如果繼續爬取,請按回車(退出輸入quit)") if command == "quit": # 如果停止爬取,則輸入 quit self.switch = False # 每次循環,page頁碼自增1 self.page += 1 print "謝謝使用!" if __name__ == "__main__": duanziSpider = Spider() duanziSpider.startWork()

可以按回車接着爬取下一頁內容,輸入QUIT退出。

 爬取后的內容:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM