python在做爬蟲的時候,會利用到urllib提供的功能,就是利用程式去執行各種HTTP請求。如果要模拟浏覽器完成特定功能,需要把請求僞裝成浏覽器。僞裝的方法是先監控浏覽器發出的請求,再根據浏覽器的請求頭來僞裝,User-Agent頭就是用來辨別浏覽器的。另外随着python的版本不一緻會出現些差異,如下
Py2.x:
- Urllib庫
- Urllin2庫
Py3.x:
- Urllib庫
變化:
- 在Pytho2.x中使用import urllib2——-對應的,在Python3.x中會使用import urllib.request,urllib.error。
- 在Pytho2.x中使用import urllib——-對應的,在Python3.x中會使用import urllib.request,urllib.error,urllib.parse。
- 在Pytho2.x中使用import urlparse——-對應的,在Python3.x中會使用import urllib.parse。
- 在Pytho2.x中使用import urlopen——-對應的,在Python3.x中會使用import urllib.request.urlopen。
- 在Pytho2.x中使用import urlencode——-對應的,在Python3.x中會使用import urllib.parse.urlencode。
- 在Pytho2.x中使用import urllib.quote——-對應的,在Python3.x中會使用import urllib.request.quote。
- 在Pytho2.x中使用cookielib.CookieJar——-對應的,在Python3.x中會使用http.CookieJar。
- 在Pytho2.x中使用urllib2.Request——-對應的,在Python3.x中會使用urllib.request.Request。
快速爬取一個網頁
#作者微信:jialee918
__author__ = 'jiali765'
# -*- coding:utf-8 -*-
import urllib.request
import re
class Spider:
def __init__(self):
self.siteURL = 'http://mm.taobao.com/json/request_top_list.htm'
def getPage(self, pageIndex):
url = self.siteURL + "?page=" + str(pageIndex)
print(url)
request = urllib.request.Request(url)
response = urllib.request.urlopen(request)
return response.read().decode('gbk')
def getContents(self, pageIndex):
page = self.getPage(pageIndex)
pattern = re.compile(
'<div class="list-item".*?pic-word.*?<a href="(.*?)" target="_blank" rel="external nofollow" .*?<img src="(.*?)".*?<a class="lady-name.*?>(.*?)</a>.*?<strong>(.*?)</strong>.*?<span>(.*?)</span>',
re.S)
items = re.findall(pattern, page)
for item in items:
print(item[0], item[1], item[2], item[3], item[4])
spider = Spider()
spider.getContents(1)
浏覽器的模拟
應用場景:有些網頁為了防止别人惡意采集其資訊是以進行了一些反爬蟲的設定,而我們又想進行爬取。
解決方法:設定一些
Headers
資訊(
User-Agent
),模拟成浏覽器去通路這些網站。
#作者微信:jialee918
__author__ = 'jiali765'
# -*- coding:utf-8 -*-
import urllib.request
import urllib.parse
url = 'http://www.baidu.com'
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36'
}
request = urllib.request.Request(url, headers=header)
reponse = urllib.request.urlopen(request).read()
fhandle = open("./baidu.html", "wb")
fhandle.write(reponse)
fhandle.close()
代理伺服器的設定
應用場景:使用同一個IP去爬取同一個網站上的網頁,久了之後會被該網站伺服器屏蔽。
解決方法:使用代理伺服器。 (使用代理伺服器去爬取某個網站的内容的時候,在對方的網站上,顯示的不是我們真實的IP位址,而是代理伺服器的IP位址)
def use_proxy(proxy_addr,url):
import urllib.request
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('utf8')
return data
proxy_addr='61.163.39.70:9999'
data=use_proxy(proxy_addr,'http://www.baidu.com')
print(len(data))
Cookie
的使用
Cookie
應用場景:爬取的網頁涉及登入資訊。通路每一個網際網路頁面,都是通過
HTTP
協定進行的,而
HTTP
協定是一個無狀态協定,所謂的無狀态協定即無法維持會話之間的狀态。
#作者微信:jialee918
__author__ = 'jiali765'
# -*- coding:utf-8 -*-
import urllib.request
import urllib.parse
import urllib.error
import http.cookiejar
url='http://bbs.chinaunix.net/member.php?mod=logging&action=login&loginsubmit=yes&loginhash=La2A2'
data={
'username':'zhanghao',
'password':'mima',
}
postdata=urllib.parse.urlencode(data).encode('utf8')
header={
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}
request=urllib.request.Request(url,postdata,headers=header)
#使用http.cookiejar.CookieJar()建立CookieJar對象
cjar=http.cookiejar.CookieJar()
#使用HTTPCookieProcessor建立cookie處理器,并以其為參數建構opener對象
cookie=urllib.request.HTTPCookieProcessor(cjar)
opener=urllib.request.build_opener(cookie)
#将opener安裝為全局
urllib.request.install_opener(opener)
try:
reponse=urllib.request.urlopen(request)
except urllib.error.HTTPError as e:
print(e.code)
print(e.reason)
fhandle=open('./test1.html','wb')
fhandle.write(reponse.read())
fhandle.close()
url2='http://bbs.chinaunix.net/forum-327-1.html' #打開test2.html檔案,會發現此時會保持我們的登入資訊,為已登入狀态。也就是說,對應的登入狀态已經通過Cookie儲存。
reponse2=urllib.request.urlopen(url)
fhandle2=open('./test2.html','wb')
fhandle2.write(reponse2.read())
fhandle2.close()
Get
urllib的
request
子產品可以非常友善地抓取URL内容,也就是發送一個GET請求到指定的頁面,然後傳回HTTP的響應:
例如,對豆瓣的一個URL
https://api.douban.com/v2/book/2129650
進行抓取,并傳回響應:
from urllib import request
with request.urlopen('https://api.douban.com/v2/book/2129650') as f:
data = f.read()
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', data.decode('utf-8'))
Post
如果要以POST發送一個請求,隻需要把參數
data
以bytes形式傳入。
我們模拟一個微網誌登入,先讀取登入的郵箱和密碼,然後按照weibo.cn的登入頁的格式以
username=xxx&password=xxx
的編碼傳入:
#作者微信:jialee918
__author__ = 'jiali765'
# -*- coding:utf-8 -*-
from urllib import request, parse
print('Login to weibo.cn...')
email = input('Email: ')
passwd = input('Password: ')
login_data = parse.urlencode([
('username', email),
('password', passwd),
('entry', 'mweibo'),
('client_id', ''),
('savestate', '1'),
('ec', ''),
('pagerefer', 'https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F')
])
req = request.Request('https://passport.weibo.cn/sso/login')
req.add_header('Origin', 'https://passport.weibo.cn')
req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')
with request.urlopen(req, data=login_data.encode('utf-8')) as f:
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', f.read().decode('utf-8'))
如果登入成功,我們獲得的響應如下:
Status: 200 OK
Server: nginx/1.2.0
...
Set-Cookie: SSOLoginState=1432620126; path=/; domain=weibo.cn
...
Data: {"retcode":20000000,"msg":"","data":{...,"uid":"1658384301"}}
如果登入失敗,我們獲得的響應如下:
...
Data: {"retcode":50011015,"msg":"\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef","data":{"username":"[email protected]","errline":536}}