Python3網路爬蟲開發實戰——第3章 基本庫的使用

大叔小py發表於2019-02-25

作者講了兩個庫,一個是urllib,一個是requests。因為後者更為方便,強大,直接看requests就好

3.2 使用 requests

請求網頁: r = requests.get(url,params=data)
是否得到響應:r.status_code
返回的結果如果是str型別,可以用json()解析並返回字典格式,但如果不是str型別,會丟擲異常
r.content: 返回抓取物件的二進位制碼,這樣知道連結就可以獲取圖片,音樂和視訊,因為它們本質上就是二進位制資料…(暗爽~)

import requests
r = requests.get('https://www.baidu.com/img/bd_logo1.png')
with open('bdlogo.png','wb') as f:
	f.write(r.content)

有些網站不給爬,我們就得修改headers
先給headers一個值,字典型別,如:

headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
                          'Chrome/65.0.3325.162 Safari/537.36'}
r.requests.get(url,headers=headers)

r.requests.post():跟get差不多,不過get就是在網址後面加資料,post能傳送資料和檔案,用的是字典型別

files = {'file':open('bdlogo.png','rb')}	# 以二進位制的形式開啟檔案
r = requests.post("http://httpbin.org/post",files=files)

r.cookies:獲取cookies,作用是保持網站的登入狀態。先登入一次網站,然後然cookies內容複製下來,貼上到headers裡

headers = {'Cookies': '貼上Cookies',
			'Host':'www.zhihu.com',
			'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
                          'Chrome/65.0.3325.162 Safari/537.36'}
r.requests.get(url,headers=headers)

這樣就登入成功了


在用get()和post()時,是相當於用了兩個瀏覽器開啟網頁。這樣就會出現一個登入了網站,另一個沒有登入的情況。這時我們就要用Session()

import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)

有些網站需要檢查SSL證書,我們可以用verify=False引數來跳過,但會出現紅字警告,我們可以採用忽略警告的方式

import requests
from requests.packages import urllib3
urllib3.disable_warnings()
r = requests.get(url,verify=False)
print(r.status_code)

網站對於頻繁的請求,會彈出驗證碼,或封IP,這時需要用上代理。用socks5代理,需要先安裝
requests[socks] 這個庫

import requests

proxies = {
    "http": "http://10.10.1.10:3128",	# 代理純屬虛構
    "https": "http://user:password@10.10.1.10:1080/",	# 有些代理需要使用者名稱和密碼
    "https": "socks5://user:password@host:port"
}
r = requests.get('https://www.taobao.com',proxies=proxies)
print(r.status_code)

有些網站特別是國外的,我們就設定超時,超過設定時間就報錯, 還有些需要身份驗證,輸入使用者名稱和密碼的,用auth

r.requests.get(url, auth=('username','password'), timeout=10)

還可以想要傳送的請求先打個包。然後一起傳送出去。

from requests import Request,Session

url = 'http://httpbin.org/post'
data = {
    'name': 'germey'
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
                  'Chrome/65.0.3325.162 Safari/537.36'
}
s = Session()
req = Request('POST', url, data=data, headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)
3.3 正規表示式

常用的匹配規則,有需要就翻一下,能記就記
通用匹配: 點星 .* ,能匹配所有任意字元,,但會涉及到貪婪匹配。避免貪婪就在*後面加個“?”。我們儘量做非貪婪匹配。
html節點經常會有換行,match(’’,content,re.S),用上re.S,就可以匹配節點與節點間的換行,
較常用的還有re.I,忽略大小寫匹配
為了匹配方便,我們儘量使用search(),少用match
findall()獲取 匹配的所有內容
sub()把不需要的字元去掉

3.4 抓取貓眼電影排行

抓取TOP100的電影名稱、時間、評分、圖片等
目標網址:https://maoyan.com/board/4

目標有分頁,每頁10部電影,點第二頁觀察網址的變化
第二頁:https://maoyan.com/board/4?offset=10
第三頁:https://maoyan.com/board/4?offset=20

可見,offset是偏移量,每頁顯示10個,顯示 n+1 到 n+10 名次的電影。。要獲取TOP100,就分開請求10次。然後用正規表示式提取相關資訊

import requests
import re
import json
from requests.exceptions import RequestException
import time


def parse_one_page(html):	# 正則提取
    pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a'
                         + '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
                         + '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
    items = re.findall(pattern, html)
    for item in items:	# 處理結果,遍歷提取並生成字典
        yield {
            'index':item[0],
            'image':item[1],
            'title':item[2].strip(),
            'actor':item[3].strip()[3:] if len(item[3]) > 3 else '',
            'time':item[4].strip()[5:] if len(item[4]) > 5 else '',
            'score':item[5].strip() + item[6].strip()
        }


def get_one_page(url):
    try:
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
                          'Chrome/65.0.3325.162 Safari/537.36'
        }
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        return None

def write_to_file(content):	 # 寫入檔案
    with open('result.txt','a',encoding='utf-8') as f:
        print(type(json.dumps(content))) 	# 實現字典的序列化
        f.write(json.dumps(content,ensure_ascii=False)+'\n') # ensure_ascii=False ,顯示中文,不然顯示unicode編碼

def main(offset):
    url = 'https://maoyan.com/board/4?offset='+str(offset)
    html = get_one_page(url)
    for item in parse_one_page(html):
        print(item)
        write_to_file(item)

if __name__ == '__main__':
    for i in range(10):
        main(offset=i *10)  # 呼叫一次就下一頁
        time.sleep(1)

相關文章