爬蟲1——urllib的使用


一、什么是爬蟲

1、爬蟲Spider的概念

爬蟲用於爬取數據,又稱之為數據采集程序。

爬取的數據來源於網絡,網絡中的數據可以是由WEB服務器(Nginx/Apache),數據庫服務器(MySQL、Redis),索引庫(ElastichSearch),大數據(Hbase/Hive),視頻/圖片庫(FTP),雲存儲(OSS)等提供。

爬取的數據是公開的,非盈利的。

2、Python爬蟲

使用Python編寫的爬蟲腳本(程序)可以完成定時,定量,指定目標(web站點)的數據爬取,主要使用多(單)線程/進程、網絡請求庫、數據解析、數據存儲、任務調度等相關技術。

Python爬蟲工程師,可以完成接口測試,功能性測試,性能測試,集成測試。

二、爬蟲與WEB后端服務之間的關系

爬蟲使用網絡請求庫,相當於客戶端請求,Web后端服務根據請求響應數據。

爬蟲即向Web服務器發起HTTP請求,正確的接收響應數據,然后根據數據的類型(Content-Type)進行數據的解析及存儲。

爬蟲程序在發起請求前,需要偽造一個瀏覽器(User-Agent指定頭),然后再向服務器發起請求,響應200的成功率高很多。

三、Python爬蟲技術的相關庫

1、網絡請求

  • urllib
  • requests
  • selenium(UI自動測試,動態js渲染)
  • appium(手機APP的爬蟲或UI測試)

2、數據解析

  • re正則
  • xpath
  • bs4
  • json

3、數據存儲

  • pymysql
  • mongodb
  • elasticsearch

4、多任務

  • 多線程(threading)、線程隊列 queue
  • 協程(asynio、gevent/eventlet)

5、爬蟲框架

  • scrapy
  • scrapy-redis分布式(多機爬蟲)

四、常見反爬蟲的策略

  • UA(User-Agent)策略
  • 登錄限制(Cookie)策略
  • 請求頻次(IP代理)策略
  • 驗證碼(圖片-雲打碼,點觸驗證、滑塊)策略
  • 動態js策略(Selenium/Splash/api接口)策略

五、爬蟲庫urllib

1、urllib.request模塊

1.1、簡單請求

from urllib.request import urlopen

# 發起網絡請求
resp = urlopen("http://www.hao123.com")
assert resp.code == 200
print("請求成功")
# 保存請求的網頁
# f變量接收open()函數返回對象的__enter__()返回的就結果

   with open("hao123.html", "wb") as f: f.write(resp.read())

urlopen(url, data=None)可以直接發起url請求,如果data不為空時,默認是POST請求,反之為GET請求。

resp是http.client.HTTPResponse類對象

1.2、帶請求頭的請求

"""
初次使用urllib實現爬蟲的數據請求
urllib.request.urlopen(url)  發起get請求
urllib.parse.quote()   講中文進行url編碼
urllib.request.urlretrieve(url, filename)  下載url保存到filename
"""

from urllib.request import urlopen, urlretrieve, Request
from urllib.parse import quote

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

def search_baidu(wd='李志'):
    # 網絡請求資源接口(url)
    url = 'https://www.baidu.com/s?wd=%s'

    # 生成請求對象,封裝請求的url和頭header
    request = Request(url % quote(wd), headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
        'Cookie': 'PSTM=1577115106; BAIDUID=94178A0C4E70392F8094399EE47D06E8:FG=1; BIDUPSID=66B8977AF3BB990218FACD41E237E148; BDUSS=o2amI1SjlZQUZHOTJiTzZoRWVwN051Z2pOSm5hRm12OGd6YUx4VFRaUmtvbkZlRVFBQUFBJCQAAAAAAAAAAAEAAAAi-ccWaHVpeWljaGFubWlhbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQVSl5kFUpeMX; BD_UPN=12314753; BD_HOME=1; H_PS_PSSID=30974_1429_21108_30997_30824_30717; delPer=0; BD_CK_SAM=1; PSINO=6; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; COOKIE_SESSION=93270_0_5_4_10_6_0_0_4_3_0_3_93360_0_4_0_1583674230_0_1583674226%7C9%230_2_1577625718%7C1; sug=3; sugstore=0; ORIGIN=0; bdime=0; H_PS_645EC=ee56%2Bh2%2FYYj4EN%2FXrG%2FdO5beNAv52Z9Yz4fZg21AWgMroxtYWtP17XRR1VM'
    })
    response = urlopen(request)
    assert response.code == 200
    print("請求成功")

    # 讀取響應的數據
    bytes_ = response.read()
    with open('%s.html' % wd, "wb") as file:
        file.write(bytes_)

 2、urllib.parse模塊

此模塊有兩個核心函數:

quote()僅對中文字符穿進行url編碼

urlencode()可以針對一個字典中所有的values進行編碼,然后轉成key=value&key=value字符串。

from urllib.parse import quote
from urllib.parse import urlencode
quote("李志")
'%E6%9D%8E%E5%BF%97'
urlencode({"姓名":"李志"})
'%E5%A7%93%E5%90%8D=%E6%9D%8E%E5%BF%97'

 六、百度翻譯的實現

'''
應用:百度翻譯
urllib.request.Request
urllib.request.urlopen()
urllib.parse.urlencode()
發起post請求
'''
import json
from urllib.parse import urlencode
from urllib.request import Request, urlopen


url = 'https://fanyi.baidu.com/sug'

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
    'cookie': 'PSTM=1577115106; BAIDUID=94178A0C4E70392F8094399EE47D06E8:FG=1; '
              'BIDUPSID=66B8977AF3BB990218FACD41E237E148; BDUSS=o2amI1SjlZQUZHOTJiTzZo'
              'RWVwN051Z2pOSm5hRm12OGd6YUx4VFRaUmtvbkZlRVFBQUFBJCQAAAAAAAAAAAEAAAAi-ccWaHVpeWl'
              'jaGFubWlhbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQVSl5kFUpeMX;'
              ' to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22valu'
              'e%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1;'
              ' FANYI_WORD_SWITCH=1; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; delPer=0; PSINO=6; '
              'BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; '
              'BDRCVFR[-pGxjrCMryR]=mk3SLVN4HKm; H_PS_PSSID=30974_1429_21108_30997_30824; '
              'Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1581948391,1583753885; '
              'from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22'
              '%7D%2C%7B%22value%22%3A%22dan%22%2C%22text%22%3A%22%u4E39%u9EA6%u8BED%22%7D%2C%7B%2'
              '2value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D; Hm_lpvt_64ecd82404c51e03dc91cb'
              '9e8c025574=1583753974; __yjsv5_shitong=1.0_7_f938cb5bed75810c7f54daa26e4d74d416c7_300_1583753976124_'
              '219.145.32.239_2b22827f;yjs_js_security_passport=afa2db6dc7814c5d0875abbf087495d6b1b9b20f_1583753976_js'
}


def fanyi(kw):
    data = {
        'kw': kw
    }
    # Request()中的data參數是byte類型
    # data不為空時,就是post請求
    req = Request(url, data=urlencode(data).encode("utf-8"))
    resp = urlopen(req)
    assert resp.code == 200
    json_data = resp.read()  # byte
    content_encode = resp.getheader("Content-Type")
    content_encode = "utf-8" if content_encode is None else content_encode.split("=")[-1]
    return json.loads(json_data.decode(content_encode))  # loads函數將json字串變為字典


if __name__ == '__main__':
    print(fanyi("orange"))

七、GET請求多個頁面

"""
復雜的get請求,多頁面請求下載
"""
import random
import time
from urllib.request import Request, urlopen
from urllib.parse import urlencode


url = "https://www.baidu.com/s?"
params = {
    'wd': '',
    'pn': 0   # 0, 10, 20, 30...= (n-1)*10
}

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
    'cookie': 'PSTM=1577115106; BAIDUID=94178A0C4E70392F8094399EE47D06E8:FG=1; '
              'BIDUPSID=66B8977AF3BB990218FACD41E237E148; BDUSS=o2amI1SjlZQUZHOTJiTzZo'
              'RWVwN051Z2pOSm5hRm12OGd6YUx4VFRaUmtvbkZlRVFBQUFBJCQAAAAAAAAAAAEAAAAi-ccWaHVpeWl'
              'jaGFubWlhbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQVSl5kFUpeMX;'
              ' to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22valu'
              'e%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1;'
              ' FANYI_WORD_SWITCH=1; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; delPer=0; PSINO=6; '
              'BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; '
              'BDRCVFR[-pGxjrCMryR]=mk3SLVN4HKm; H_PS_PSSID=30974_1429_21108_30997_30824; '
              'Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1581948391,1583753885; '
              'from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22'
              '%7D%2C%7B%22value%22%3A%22dan%22%2C%22text%22%3A%22%u4E39%u9EA6%u8BED%22%7D%2C%7B%2'
              '2value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D; Hm_lpvt_64ecd82404c51e03dc91cb'
              '9e8c025574=1583753974; __yjsv5_shitong=1.0_7_f938cb5bed75810c7f54daa26e4d74d416c7_300_1583753976124_'
              '219.145.32.239_2b22827f;yjs_js_security_passport=afa2db6dc7814c5d0875abbf087495d6b1b9b20f_1583753976_js'
}

def pages_get(wd):
    params['wd'] = wd
    for page in range(1, 101):
        params['pn'] = (page-1) * 10

        page_url = url + urlencode(params)
        resp = urlopen(Request(page_url, headers=headers))
        assert resp.code == 200
        filename = "baidu_pages/%s-%s.html" % (wd, page)
        time.sleep(random.random())
        with open(filename, 'wb') as f:
            bytes_ = resp.read()
            f.write(bytes_)
            print('下載%s頁成功' % page)



if __name__ == '__main__':
    pages_get("李志")

八、Handler處理器

request對象不能攜帶cookie,也不能使用代理,所以引入了Handler處理器、自定義Opener。

1、步驟

創建Handler對象

handler = urllib.request.HTTPHandler()

創建opener對象

opener= urllib.request.build_opener(handler)

創建Request對象

request = urllib.request.Request(url=url,headers=headers

發送Reques請求

response = opener.open(request)

九、cookie庫

1、cookie庫能干啥?

自動幫我們保存登陸的cookie信息

2、cookie庫配置

創建一個CookieJar對象

from http.cookiejar import CookieJar
cookie = cookiejar.CookieJar()

使用cookiejar對象,創建一個handler對象

handler = urllib.request.HTTPCookieProcessor(cookie)

使用handler創建一個opener

opener = urllib.request.build_opener(handler)

通過opener登錄

handler會自動的保存登錄之后的cookie

import urllib.request
import http.cookiejar as cookiejar


post_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=20182122180'

data = {
    'rkey':'1c7df63368df7ce73c234de26178ec11',
    'password':'19870115',
    'origURL':'http://www.renren.com/home',
    'key_id':'1',
    'icode':'',
    'f':'http://www.renren.com/224549540',
    'email':'dqsygcz@126.com',
    'domain':'renren.com',
    'captcha_type':'web_login',
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36',
    'Referer': 'http://www.renren.com/SysHome.do'
}

# 轉換字節
data = urllib.parse.urlencode(data).encode('utf-8')
# 定制請求對象
request = urllib.request.Request(url=post_url, headers=headers, data=data)
# 創建cookie對象
cookie = cookiejar.CookieJar()
# 創建handler對象
handler = urllib.request.HTTPCookieProcessor(cookie)
# 創建opener對象
opener = urllib.request.build_opener(handler)
# 使用opener對象發送請求
response = opener.open(request)
print(response.getcode())

十、代理服務器

1、什么是代理服務器

一種重要的服務器安全功能,它的工作主要在開放系統互聯(OSI)模型的會話層,從而起到防火牆的作用

FQ,是指繞過相應的IP封鎖、內容過濾、域名劫持、流量限制等。

2、代理的常用功能

突破自身IP訪問限制,訪問國外站點。

訪問一些單位或團體內部資源

提高訪問速度,通常代理服務器都設置一個較大的硬盤緩沖區,當有外界的信息通過時,同時也將其保存到緩沖區中,當其他用戶再訪問相同的信息時, 則直接由緩沖區中取出信息,傳給用戶,以提高訪問速度。

隱藏真實IP。

3、代碼配置

創建Reuqest對象

創建ProxyHandler對象

用handler對象創建opener對象

使用opener.open函數發送請求

# 創建代理handler對象
handler = urllib.request.ProxyHandler(proxies={'http':'114.212.80.2:3128'})

# 創建opener 
opener = urllib.request.build_opener(handler)
# opener.open 替代 urllib.request.urlopen
response = opener.open(request)

with open('ipp.html','wb') as fp:
    fp.write(response.read())

 


免責聲明!

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



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