Python——爬蟲(一)

爬蟲準備工作

  • 參考資料
    • python網絡數據採集 ’ 圖靈工業出版
    • 精通python爬蟲框架Scrapy ’ 人民郵電出版社
    • python3網絡爬蟲
    • Scrapy官方教程
  • 前提知識
    • url
    • http協議
    • web前端 ’ html, css, js
    • ajax
    • re, xpath
    • xml

爬蟲簡介

  • 爬蟲定義:網絡爬蟲(又被稱爲網頁蜘蛛、網絡機器人,在FOAF社區中間,更經常的稱爲網頁追逐者),
    是一種按照一定的規則,自動地抓取萬維網信息的程序或者腳本
    另外一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲

  • 兩大特徵

    • 能按作者要求下載數據或者內容
    • 能自動在網絡上流竄
  • 三大步驟

    • 下載網頁
    • 提取正確的信息
    • 根據一定規則自動跳到另外的網頁上執行上兩步內容
  • 爬蟲分類

    • 通用爬蟲
    • 專用爬蟲(聚焦爬蟲)
  • Python網絡包簡介

    • python2.x:urllib,urllib2,urllib3,httplib,httplib2,requests
    • python3.x:urllib,urllib3,httplib2,requests
    • python2:urllib和urllib2配合使用,或者requests
    • python3:urllib,requests

urllib

  • 包含模塊
    • urllib.request: 打開和讀取urls
    • urllib.error: 包含urllib.request產生的常見的錯誤,使用try捕捉
    • urllib.parse: 包含解析url的方法
    • urllib.robotparse: 解析robots.txt文件
    • 案例v01
    '''
    案例v01
    使用urllib.request請求一個網頁內容,並把內容打印出來
    '''
    from urllib import request
    
    if __name__ == '__main__':
        url = "https://www.zhaopin.com/taiyuan/"
        # 打開相應url並把相應頁面作爲返回
        rsp = request.urlopen(url)
    
        # 把返回的結果讀取出來
        # 讀取出來內容類型爲bytes
        html = rsp.read()
        print(type(html))
    
        # 如果想把bytes內容轉換成字符串,需要解碼
        print(html.decode())
    
  • 網頁編碼問題解決
    • chardet 可以自動檢測頁面文件的編碼格式,但是,可能有誤
    • 需要安裝,conda install chardet
    • 案例v02
    '''
    案例v02
    利用request下載頁面
    自動檢測頁面編碼
    
    '''
    import urllib
    import chardet
    
    if __name__ == '__main__':
        url = "http://stock.eastmoney.com/news/1407,20170807763593890.html"
    
        rsp = urllib.request.urlopen(url)
    
        html = rsp.read()
    
        # 利用chardet自動檢測
        cs = chardet.detect(html)
        print(type(cs))
        print(cs)
    
        # 使用get取值保證不會出錯
        html = html.decode(cs.get("encoding", "utf-8"))
        print(html)
    
  • urlopen的返回對象
    • 案例v03
    # 案例v03
    import urllib
    import chardet
    
    if __name__ == '__main__':
        url = "http://stock.eastmoney.com/news/1407,20170807763593890.html"
    
        rsp = urllib.request.urlopen(url)
    
        print(type(rsp))
        print(rsp)
    
        print("URL: {0}".format(rsp.geturl()))
        print("Info: {0}".format(rsp.info()))
        print("Code: {0}".format(rsp.getcode()))
    
        html = rsp.read()
    
        # 使用get取值保證不會出錯
        html = html.decode()
    
    • geturl: 返回請求對象的url
    • info:請求反饋對象的meta信息
    • getcode:返回http code
  • request.data 的使用
    • 訪問網絡的兩種方法
      • get:
        • 利用參數給服務器傳遞信息
        • 參數爲dict,然後用parse編碼
        • 案例v04
         # 案例v04
         from urllib import request, parse
        
         '''
         掌握對url進行參數編碼的方法
         需要使用parse模塊 
         '''
         
         if __name__ == '__main__':
             url = "http://www.baidu.com/s?"
             wd = input("Input your keyword: ")
         
             # 要想使用data,需要使用字典結構
             qs = {
                 "wd": wd
             }
         
             # 轉換url編碼
             qs = parse.urlencode(qs)
             print(qs)
         
             fullurl =url + qs
             print(fullurl)
         
             # 如果直接用可讀的帶參數的url,是不能訪問的
             # fullurl = "http://www.baidu.com/s?wd=大熊貓"
         
             rsp = request.urlopen(fullurl)
         
             html = rsp.read()
         
             # 使用get取值保證不會出錯
             html = html.decode()
         
             print(html)
        
      • post
        • 一般向服務器傳遞參數使用
        • post是把信息自動加密處理
        • 如果想使用post信息,需要用data參數
        • 使用post,意味着http的請求有可能需要更改:
          • Content-Type:application/x-www.form-urlencode
          • Content-Length: 數據長度
          • 簡而言之,一旦更改請求方法,請注意其他請求頭部信息相適應
        • urllib.parse.urlencode可以將字符串自動轉換成上面的格式
        • 案例v05
         '''
         案例v05
         利用parse模塊模擬post請求
         分析百度詞典
         分析步驟:
         1. 打開F12
         2. 嘗試輸入單詞girl,發現每次敲一個字母后都有請求
         3. 請求地址是 https://fanyi.baidu.com/sug
         4. 利用 Network-All-Headers 查看,發現FormData的值是 kw:girl
         5. 檢查返回內容格式,發現返回的是json格式內容==>需要用到json包
         '''
         
         from urllib import request, parse
         # 負責處理json格式的模塊
         import json
         
         '''
         大致流程是:
         1. 利用data構造內容,然後urlopen打開
         2. 返回一個json格式的結果
         3. 結果就應該是girl的釋義
         '''
         
         baseurl = 'https://fanyi.baidu.com/sug'
         
         # 存放用來模擬form的數據一定是dict格式
         data = {
             # girl是翻譯輸入的英文內容,應該是由用戶輸入,此時使用硬編碼
             'kw': 'girl'
         }
         
         # 需要使用parse模塊對data進行編碼
         data = parse.urlencode(data).encode('utf-8')
         print(type(data))
         
         # 我們需要構造一個請求頭,請求頭部應該至少包含傳入的數據的長度
         # request要求傳入的請求頭是一個dict格式
         
         headers = {
             # 因爲使用post請求,至少應該包含content-length 字段
             'Content-Length':len(data)
         }
         
         # 有了headers,data,url,就可以嘗試發出請求了
         
         rsp = request.urlopen(baseurl, data=data)
         
         json_data = rsp.read().decode('utf-8')
         print(type(json_data))
         print(json_data)
         
         # 把json字符串轉化成字典
         json_data = json.loads(json_data)
         print(type(json_data))
         print(json_data)
         
         for item in json_data['data']:
             print(item['v'], "--", item['v'])
        
         <class 'bytes'>
          <class 'str'>
          {"errno":0,"data":[{"k":"girl","v":"n. \u5973\u5b69; \u59d1\u5a18; \u5973\u513f; \u5e74\u8f7b\u5973\u5b50; \u5973\u90ce;"},{"k":"girls","v":"n. \u5973\u5b69; \u59d1\u5a18; \u5973\u513f; \u5e74\u8f7b\u5973\u5b50; \u5973\u90ce;  girl\u7684\u590d\u6570;"},{"k":"girlfriend","v":"n. \u5973\u670b\u53cb; \u5973\u60c5\u4eba; (\u5973\u5b50\u7684)\u5973\u4f34\uff0c\u5973\u53cb;"},{"k":"girl friend","v":" \u672a\u5a5a\u59bb; \u5973\u6027\u670b\u53cb;"},{"k":"Girls' Generation","v":" \u5c11\u5973\u65f6\u4ee3\uff08\u97e9\u56fdSM\u5a31\u4e50\u6709\u9650\u516c\u53f8\u4e8e2007\u5e74\u63a8\u51fa\u7684\u4e5d\u540d\u5973\u5b50\u5c11\u5973\u7ec4\u5408\uff09;"}]}
          <class 'dict'>
          {'errno': 0, 'data': [{'k': 'girl', 'v': 'n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;'}, {'k': 'girls', 'v': 'n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;  girl的複數;'}, {'k': 'girlfriend', 'v': 'n. 女朋友; 女情人; (女子的)女伴,女友;'}, {'k': 'girl friend', 'v': ' 未婚妻; 女性朋友;'}, {'k': "Girls' Generation", 'v': ' 少女時代(韓國SM娛樂有限公司於2007年推出的九名女子少女組合);'}]}
          n. 女孩; 姑娘; 女兒; 年輕女子; 女郎; -- n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;
          n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;  girl的複數; -- n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;  girl的複數;
          n. 女朋友; 女情人; (女子的)女伴,女友; -- n. 女朋友; 女情人; (女子的)女伴,女友;
           未婚妻; 女性朋友; --  未婚妻; 女性朋友;
           少女時代(韓國SM娛樂有限公司於2007年推出的九名女子少女組合); --  少女時代(韓國SM娛樂有限公司於2007年推出的九名女子少女組合);
        
        • 爲了更多的設置請求信息,單純的通過urlopen函數不太好用
        • 需要利用request.Request 類
        • 案例v06
         '''
         案例v06
         任務要求和內容跟v05一樣
         本案例只是利用Request來實現v05的內容
         
         利用parse模塊模擬post請求
         分析百度詞典
         分析步驟:
         1. 打開F12
         2. 嘗試輸入單詞girl,發現每次敲一個字母后都有請求
         3. 請求地址是 https://fanyi.baidu.com/sug
         4. 利用 Network-All-Headers 查看,發現FormData的值是 kw:girl
         5. 檢查返回內容格式,發現返回的是json格式內容==>需要用到json包
         '''
         
         from urllib import request, parse
         # 負責處理json格式的模塊
         import json
         
         '''
         大致流程是:
         1. 利用data構造內容,然後urlopen打開
         2. 返回一個json格式的結果
         3. 結果就應該是girl的釋義
         '''
         
         baseurl = 'https://fanyi.baidu.com/sug'
         
         # 存放用來模擬form的數據一定是dict格式
         data = {
             # girl是翻譯輸入的英文內容,應該是由用戶輸入,此時使用硬編碼
             'kw': 'girl'
         }
         
         # 需要使用parse模塊對data進行編碼
         data = parse.urlencode(data).encode('utf-8')
         
         # 我們需要構造一個請求頭,請求頭部應該至少包含傳入的數據的長度
         # request要求傳入的請求頭是一個dict格式
         
         headers = {
             # 因爲使用post請求,至少應該包含content-length 字段
             'Content-Length':len(data)
         }
         
         # 構造一個Request的實例
         
         req = request.Request(url=baseurl, data=data, headers=headers)
         
         # 因爲已經構造了一個Request的請求實例,則所有的請求信息都可以封裝在Request實例中
         rsp = request.urlopen(req)
         
         json_data = rsp.read().decode('utf-8')
         print(type(json_data))
         print(json_data)
         
         # 把json字符串轉化成字典
         json_data = json.loads(json_data)
         print(type(json_data))
         print(json_data)
         
         for item in json_data['data']:
             print(item['v'], "--", item['v'])
        
         <class 'str'>
          {"errno":0,"data":[{"k":"girl","v":"n. \u5973\u5b69; \u59d1\u5a18; \u5973\u513f; \u5e74\u8f7b\u5973\u5b50; \u5973\u90ce;"},{"k":"girls","v":"n. \u5973\u5b69; \u59d1\u5a18; \u5973\u513f; \u5e74\u8f7b\u5973\u5b50; \u5973\u90ce;  girl\u7684\u590d\u6570;"},{"k":"girlfriend","v":"n. \u5973\u670b\u53cb; \u5973\u60c5\u4eba; (\u5973\u5b50\u7684)\u5973\u4f34\uff0c\u5973\u53cb;"},{"k":"girl friend","v":" \u672a\u5a5a\u59bb; \u5973\u6027\u670b\u53cb;"},{"k":"Girls' Generation","v":" \u5c11\u5973\u65f6\u4ee3\uff08\u97e9\u56fdSM\u5a31\u4e50\u6709\u9650\u516c\u53f8\u4e8e2007\u5e74\u63a8\u51fa\u7684\u4e5d\u540d\u5973\u5b50\u5c11\u5973\u7ec4\u5408\uff09;"}]}
          <class 'dict'>
          {'errno': 0, 'data': [{'k': 'girl', 'v': 'n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;'}, {'k': 'girls', 'v': 'n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;  girl的複數;'}, {'k': 'girlfriend', 'v': 'n. 女朋友; 女情人; (女子的)女伴,女友;'}, {'k': 'girl friend', 'v': ' 未婚妻; 女性朋友;'}, {'k': "Girls' Generation", 'v': ' 少女時代(韓國SM娛樂有限公司於2007年推出的九名女子少女組合);'}]}
          n. 女孩; 姑娘; 女兒; 年輕女子; 女郎; -- n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;
          n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;  girl的複數; -- n. 女孩; 姑娘; 女兒; 年輕女子; 女郎;  girl的複數;
          n. 女朋友; 女情人; (女子的)女伴,女友; -- n. 女朋友; 女情人; (女子的)女伴,女友;
           未婚妻; 女性朋友; --  未婚妻; 女性朋友;
           少女時代(韓國SM娛樂有限公司於2007年推出的九名女子少女組合); --  少女時代(韓國SM娛樂有限公司於2007年推出的九名女子少女組合);
        

Python——爬蟲(二)

發佈了128 篇原創文章 · 獲贊 128 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章