爬蟲_chap1網絡請求

爬蟲_chap1網絡請求

01.前奏

準備工具:

1.Python3.6開發環境。
2.Pycharm 2017 professional版。
3.虛擬環境。virtualenv/virtualenvwrapper

通用/聚焦

  1. 通用爬蟲:通用爬蟲是搜索引擎抓取系統(百度、谷歌、搜狗等)的重要組成部分。主要是將互聯網上的網頁下載到本地,形成一個互聯網內容的鏡像備份。
  2. 聚焦爬蟲:是面向特定需求的一種網絡爬蟲程序,他與通用爬蟲的區別在於:聚焦爬蟲在實施網頁抓取的時候會對內容進行篩選和處理,儘量保證只抓取與需求相關的網頁信息。

02.http和https協議:

HTTP協議:全稱是HyperText Transfer Protocol,中文意思是超文本傳輸協議,是一種發佈和接收HTML頁面的方法。服務器端口號是80端口。 HTTPS協議:是HTTP協議的加密版本,在HTTP下加入了SSL層。服務器端口號是443端口。

url詳解:scheme,host,port,path,query-string,anchor

URLUniform Resource Locator的簡寫,統一資源定位符。 一個URL由以下幾部分組成:

    scheme://host:port/path/?query-string=xxx#anchor
  • scheme:代表的是訪問的協議,一般爲http或者https以及ftp等。
  • host:主機名,域名,比如www.baidu.com
  • port:端口號。當你訪問一個網站的時候,瀏覽器默認使用80端口。
  • path:查找路徑。比如:www.jianshu.com/trending/now,後面的trending/now就是path
  • query-string:查詢字符串,比如:www.baidu.com/s?wd=python,後面的wd=python就是查詢字符串。
  • anchor:錨點,後臺一般不用管,前端用來做頁面定位的。

在瀏覽器中請求一個url,瀏覽器會對這個url進行一個編碼。除英文字母,數字和部分符號外,其他的全部使用百分號+十六進制碼值進行編碼。

端口號很多時候可以省略

常用的請求方法:get獲取, post上傳

Http協議中,定義了八種請求方法。這裏介紹兩種常用的請求方法,分別是get請求和post請求。

  1. get請求:一般情況下,只從服務器獲取數據下來,並不會對服務器資源產生任何影響的時候會使用get請求。
  2. post請求:向服務器發送數據(登錄)、上傳文件等,會對服務器資源產生影響的時候會使用post請求。 以上是在網站開發中常用的兩種方法。並且一般情況下都會遵循使用的原則。但是有的網站和服務器爲了做反爬蟲機制,也經常會不按常理出牌,有可能一個應該使用get方法的請求就一定要改成post請求,這個要視情況而定。

1580872822704

請求頭header常見參數:user-angent,referer,cookie

http協議中,向服務器發送一個請求,數據分爲三部分,第一個是把數據放在url中,第二個是把數據放在body中(在post請求中),第三個就是把數據放在head中。這裏介紹在網絡爬蟲中經常會用到的一些請求頭參數:

  1. User-Agent:瀏覽器名稱。這個在網絡爬蟲中經常會被使用到。請求一個網頁的時候,服務器通過這個參數就可以知道這個請求是由哪種瀏覽器發送的。如果我們是通過爬蟲發送請求,那麼我們的User-Agent就是Python,這對於那些有反爬蟲機制的網站來說,可以輕易的判斷你這個請求是爬蟲。因此我們要經常設置這個值爲一些瀏覽器的值,來僞裝我們的爬蟲。
  2. Referer:表明當前這個請求是從哪個url過來的。這個一般也可以用來做反爬蟲技術。如果不是從指定頁面過來的,那麼就不做相關的響應。
  3. Cookiehttp協議是無狀態的。也就是同一個人發送了兩次請求,服務器沒有能力知道這兩個請求是否來自同一個人。因此這時候就用cookie來做標識。一般如果想要做登錄後才能訪問的網站,那麼就需要發送cookie信息了。

常見響應狀態碼:

  1. 200:請求正常,服務器正常的返回數據。
  2. 301:永久重定向。比如在訪問www.jingdong.com的時候會重定向到www.jd.com
  3. 302:臨時重定向。比如在訪問一個需要登錄的頁面的時候,而此時沒有登錄,那麼就會重定向到登錄頁面。
  4. 400:請求的url在服務器上找不到。換句話說就是請求url錯誤。
  5. 403:服務器拒絕訪問,權限不夠。
  6. 500:服務器內部錯誤。可能是服務器出現bug了。

03.urllib庫

urllib庫是Python中一個最基本的網絡請求庫。可以模擬瀏覽器的行爲,向指定的服務器發送一個請求,並可以保存服務器返回的數據。

urlopen函數:得到response,默認請求get,設置data成爲post

Python3urllib庫中,所有和網絡請求相關的方法,都被集到urllib.request模塊下面了,以先來看下urlopen函數基本的使用:

from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read())

實際上,使用瀏覽器訪問百度,右鍵查看源代碼。你會發現,跟我們剛纔打印出來的數據是一模一樣的。也就是說,上面的三行代碼就已經幫我們把百度的首頁的全部代碼爬下來了。一個基本的url請求對應的python代碼真的非常簡單。
以下對urlopen函數的進行詳細講解:

  1. url:請求的url。
  2. data:請求的data,如果設置了這個值,那麼將變成post請求。
  3. 返回值:返回值是一個 http.client.HTTPResponse 對象,這個對象是一個類文件句柄對象。有 read(size)readlinereadlines以及getcode 等方法。

urlretrieve函數:下載到本地

這個函數可以方便的將網頁上的一個文件保存到本地。以下代碼可以非常方便的將百度的首頁下載到本地:

from urllib import request
request.urlretrieve('http://www.baidu.com/','baidu.html')

urlencode函數:把字典數據轉換爲URL編碼的數據

用瀏覽器發送請求的時候,如果url中包含了中文或者其他特殊字符,那麼瀏覽器會自動的給我們進行編碼。而如果使用代碼發送請求,那麼就必須手動的進行編碼,這時候就應該使用urlencode函數來實現。urlencode可以把字典數據轉換爲URL編碼的數據。示例代碼如下:

from urllib import parse
data = {'name':'爬蟲基礎','greet':'hello world','age':100}
qs = parse.urlencode(data)
print(qs)

parse_qs函數:解碼

可以將經過編碼後的url參數進行解碼。示例代碼如下:

from urllib import parse
qs = "name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&greet=hello+world&age=100"
print(parse.parse_qs(qs))

urlparse和urlsplit:分割組分爲scheme,netloc,path,query,params等

有時候拿到一個url,想要對這個url中的各個組成部分進行分割,那麼這時候就可以使用urlparse或者是urlsplit來進行分割。示例代碼如下:

from urllib import request,parse

url = 'http://www.baidu.com/s?username=zhiliao'

result = parse.urlsplit(url)
# result = parse.urlparse(url)

print('scheme:',result.scheme)
print('netloc:',result.netloc)
print('path:',result.path)
print('query:',result.query)

urlparseurlsplit基本上是一模一樣的。唯一不一樣的地方是,urlparse裏面多了一個params屬性,而urlsplit沒有這個params屬性。比如有一個url爲:url = 'http://www.baidu.com/s;hello?wd=python&username=abc#1'
那麼urlparse可以獲取到hello,而urlsplit不可以獲取到。url中的params也用得比較少。

request.Request類:用自定義請求頭髮送請求(request.urlopen)

如果想要在請求的時候增加一些請求頭,那麼就必須使用request.Request類來實現。比如要增加一個User-Agent,示例代碼如下:

from urllib import request

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}
req = request.Request("http://www.baidu.com/",headers=headers)
resp = request.urlopen(req)
print(resp.read())

內涵段子爬蟲實戰作業:

  1. url鏈接:http://neihanshequ.com/bar/1/
  2. 要求:能爬取一頁的數據就可以了。

ProxyHandler處理器(代理設置):用自定義opener來使用代理

很多網站會檢測某一段時間某個IP的訪問次數(通過流量統計,系統日誌等),如果訪問次數多的不像正常人,它會禁止這個IP的訪問。
所以我們可以設置一些代理服務器,每隔一段時間換一個代理,就算IP被禁止,依然可以換個IP繼續爬取。
urllib中通過ProxyHandler來設置使用代理服務器,下面代碼說明如何使用自定義opener來使用代理

from urllib import request

# 這個是沒有使用代理的
# resp = request.urlopen('http://httpbin.org/get')
# print(resp.read().decode("utf-8"))

# 這個是使用了代理的
handler = request.ProxyHandler({"http":"218.66.161.88:31769"})

opener = request.build_opener(handler)
req = request.Request("http://httpbin.org/ip")
resp = opener.open(req)
print(resp.read())

常用的代理有:

  • 西刺免費代理IP:http://www.xicidaili.com/
  • 快代理:http://www.kuaidaili.com/
  • 代理雲:http://www.dailiyun.com/

note:

ctrl+d進入定義位置
urlparse多了一個params屬性,urlspilt沒有
www.json.cn

1580876495775

utf-8

1580876542431

header從network獲取,data固定?
referer
httpbin.org
urlopen底層也是三步走:handler->opoener->發送open

1580877024820

1580877246084

什麼是cookie:

在網站中,http請求是無狀態的。也就是說即使第一次和服務器連接後並且登錄成功後,第二次請求服務器依然不能知道當前請求是哪個用戶。cookie的出現就是爲了解決這個問題,第一次登錄後服務器返回一些數據(cookie)給瀏覽器,然後瀏覽器保存在本地,當該用戶發送第二次請求的時候,就會自動的把上次請求存儲的cookie數據自動的攜帶給服務器,服務器通過瀏覽器攜帶的數據就能判斷當前用戶是哪個了。cookie存儲的數據量有限,不同的瀏覽器有不同的存儲大小,但一般不超過4KB。因此使用cookie只能存儲一些小量的數據。

在response headers裏面看

課程是2017之前的?

cookie的格式:

Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

參數意義:

  • NAME:cookie的名字。
  • VALUE:cookie的值。
  • Expires:cookie的過期時間。
  • Path:cookie作用的路徑。
  • Domain:cookie作用的域名。
  • SECURE:是否只在https協議下起作用。

使用cookielib庫和HTTPCookieProcessor模擬登錄:

Cookie 是指網站服務器爲了辨別用戶身份和進行Session跟蹤,而儲存在用戶瀏覽器上的文本文件,Cookie可以保持登錄信息到用戶下次與服務器的會話。
這裏以人人網爲例。人人網中,要訪問某個人的主頁,必須先登錄才能訪問,登錄說白了就是要有cookie信息。那麼如果我們想要用代碼的方式訪問,就必須要有正確的cookie信息才能訪問。解決方案有兩種,第一種是使用瀏覽器訪問,然後將cookie信息複製下來,放到headers中。示例代碼如下:

from urllib import request

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
    'Cookie': 'anonymid=jacdwz2x-8bjldx; depovince=GW; _r01_=1; _ga=GA1.2.1455063316.1511436360; _gid=GA1.2.862627163.1511436360; wp=1; JSESSIONID=abczwY8ecd4xz8RJcyP-v; jebecookies=d4497791-9d41-4269-9e2b-3858d4989785|||||; ick_login=884e75d4-f361-4cff-94bb-81fe6c42b220; _de=EA5778F44555C091303554EBBEB4676C696BF75400CE19CC; p=61a3c7d0d4b2d1e991095353f83fa2141; first_login_flag=1; [email protected]; ln_hurl=http://hdn.xnimg.cn/photos/hdn121/20170428/1700/main_nhiB_aebd0000854a1986.jpg; t=3dd84a3117737e819dd2c32f1cdb91d01; societyguester=3dd84a3117737e819dd2c32f1cdb91d01; id=443362311; xnsid=169efdc0; loginfrom=syshome; ch_id=10016; jebe_key=9c062f5a-4335-4a91-bf7a-970f8b86a64e%7Ca022c303305d1b2ab6b5089643e4b5de%7C1511449232839%7C1; wp_fold=0'
}

url = 'http://www.renren.com/880151247/profile'

req = request.Request(url,headers=headers)
resp = request.urlopen(req)
with open('renren.html','w') as fp:
    fp.write(resp.read().decode('utf-8'))

但是每次在訪問需要cookie的頁面都要從瀏覽器中複製cookie比較麻煩。在Python處理Cookie,一般是通過http.cookiejar模塊和urllib模塊的HTTPCookieProcessor處理器類一起使用。http.cookiejar模塊主要作用是提供用於存儲cookie的對象。而HTTPCookieProcessor處理器主要作用是處理這些cookie對象,並構建handler對象

1580882295149

1580882471856

硬盤裏面存儲方式是utf-8???

http.cookiejar模塊

該模塊主要的類有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。這四個類的作用分別如下:

  1. CookieJar:管理HTTP cookie值、存儲HTTP請求生成的cookie、向傳出的HTTP請求添加cookie的對象。整個cookie都存儲在內存中,對CookieJar實例進行垃圾回收後cookie也將丟失。
  2. FileCookieJar (filename,delayload=None,policy=None):從CookieJar派生而來,用來創建FileCookieJar實例,檢索cookie信息並將cookie存儲到文件中。filename是存儲cookie的文件名。delayload爲True時支持延遲訪問訪問文件,即只有在需要時纔讀取文件或在文件中存儲數據。
  3. MozillaCookieJar (filename,delayload=None,policy=None):從FileCookieJar派生而來,創建與Mozilla瀏覽器 cookies.txt兼容的FileCookieJar實例。
  4. LWPCookieJar (filename,delayload=None,policy=None):從FileCookieJar派生而來,創建與libwww-perl標準的 Set-Cookie3 文件格式兼容的FileCookieJar實例。//目前這個標準還不普遍

登錄人人網:

利用http.cookiejarrequest.HTTPCookieProcessor登錄人人網。相關示例代碼如下:

from urllib import request,parse
from http.cookiejar import CookieJar#大寫??

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

def get_opener():
    cookiejar = CookieJar()
    handler = request.HTTPCookieProcessor(cookiejar)
    opener = request.build_opener(handler)
    return opener

def login_renren(opener):
    data = {"email": "[email protected]", "password": "pythonspider"}
    data = parse.urlencode(data).encode('utf-8')
    login_url = "http://www.renren.com/PLogin.do"
    req = request.Request(login_url, headers=headers, data=data)
    opener.open(req)##講課的時候這裏寫成了request.urlopen(req)導致出錯

def visit_profile(opener):
    url = 'http://www.renren.com/880151247/profile'
    req = request.Request(url,headers=headers)
    resp = opener.open(req)
    with open('renren.html','w') as fp:
        fp.write(resp.read().decode("utf-8"))

if __name__ == '__main__':
    opener = get_opener()
    login_renren(opener)
    visit_profile(opener)

保存cookie到本地:

保存cookie到本地,可以使用cookiejarsave方法,並且需要指定一個文件名:

from urllib import request
from http.cookiejar import MozillaCookieJar

cookiejar = MozillaCookieJar("cookie.txt")
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}
req = request.Request('http://httpbin.org/cookies',headers=headers)

resp = opener.open(req)
print(resp.read())
cookiejar.save(ignore_discard=True,ignore_expires=True)

從本地加載cookie:

從本地加載cookie,需要使用cookiejarload方法,並且也需要指定方法:

from urllib import request
from http.cookiejar import MozillaCookieJar

cookiejar = MozillaCookieJar("cookie.txt")
cookiejar.load(ignore_expires=True,ignore_discard=True)
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}
req = request.Request('http://httpbin.org/cookies',headers=headers)

resp = opener.open(req)
print(resp.read())

Note:
注意過期時間

???:

httpcookieprocessor??

04.requests庫

雖然Python的標準庫中 urllib模塊已經包含了平常我們使用的大多數功能,但是它的 API 使用起來讓人感覺不太好,而 Requests宣傳是 “HTTP for Humans”,說明使用更簡潔方便。

安裝和文檔地址:

利用pip可以非常方便的安裝:

pip install requests

中文文檔:http://docs.python-requests.org/zh_CN/latest/index.html
github地址:https://github.com/requests/requests

發送GET請求:

  1. 最簡單的發送get請求就是通過requests.get來調用:

    response = requests.get("http://www.baidu.com/")
    
  2. 添加headers和查詢參數:
    如果想添加 headers,可以傳入headers參數來增加請求頭中的headers信息。如果要將參數放在url中傳遞,可以利用 params 參數。相關示例代碼如下:

     import requests
    
     kw = {'wd':'中國'}
    
     headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 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返回的字節流數據,即bytes
     print(response.content)
    
     # 查看完整url地址
     print(response.url)
    
     # 查看響應頭部字符編碼
     print(response.encoding)
    
     # 查看響應碼
     print(response.status_code)
    

Note:

1580890275530

發送POST請求:

  1. 最基本的POST請求可以使用post方法:

    response = requests.post("http://www.baidu.com/",data=data)
    
  2. 傳入data數據:
    這時候就不要再使用urlencode進行編碼了,直接傳入一個字典進去就可以了。比如請求拉勾網的數據的代碼:

     import requests
    
     url = "https://www.lagou.com/jobs/positionAjax.json?city=%E6%B7%B1%E5%9C%B3&needAddtionalResult=false&isSchoolJob=0"
    
     headers = {
         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
         'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput='
     }
    
     data = {
         'first': 'true',
         'pn': 1,
         'kd': 'python'
     }#這個從網頁獲取
    
     resp = requests.post(url,headers=headers,data=data)
     # 如果是json數據,直接可以調用json方法
     print(resp.json())
    

Note:

1580890603383

使用代理:

使用requests添加代理也非常簡單,只要在請求的方法中(比如get或者post)傳遞proxies參數就可以了。示例代碼如下:

import requests

url = "http://httpbin.org/get"

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

proxy = {
    'http': '171.14.209.180:27829'
}

resp = requests.get(url,headers=headers,proxies=proxy)
with open('xx.html','w',encoding='utf-8') as fp:
    fp.write(resp.text)

演示:
1580890982727

問題:
匿名度爲 透明 ip地址有什麼用呢?

cookie:

如果在一個響應中包含了cookie,那麼可以利用cookies屬性拿到這個返回的cookie值:

import requests

url = "http://www.renren.com/PLogin.do"
data = {"email":"[email protected]",'password':"pythonspider"}
resp = requests.get('http://www.baidu.com/')
print(resp.cookies)
print(resp.cookies.get_dict())#以字典格式返回cookies

session:會話(對比urllib中ongoingopener共享cookie)

之前使用urllib庫,是可以使用opener發送多個請求,多個請求之間是可以共享cookie的。如果使用requests,也要達到共享cookie的目的,那麼可以使用requests庫給我們提供的session對象。注意,這裏的session不是web開發中的那個session,這個地方只是一個會話的對象而已。還是以登錄人人網爲例,使用requests來實現。示例代碼如下:

import requests

url = "http://www.renren.com/PLogin.do"
data = {"email":"[email protected]",'password':"pythonspider"}
headers = {
    'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
}

# 登錄
session = requests.session()
session.post(url,data=data,headers=headers)

# 訪問大鵬個人中心
resp = session.get('http://www.renren.com/880151247/profile')

print(resp.text)

1580895948662

處理不信任的SSL證書:

對於那些已經被信任的SSL證書的網站,比如https://www.baidu.com/,那麼使用requests直接就可以正常的返回響應。示例代碼如下:

resp = requests.get('http://www.12306.cn/mormhweb/',verify=False)
print(resp.content.decode('utf-8'))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章