Javascript如何實現簡單爬蟲(微軟小冰讀心術)

1.何為網絡爬蟲

網絡爬蟲(又被稱為網頁蜘蛛,網絡機器人),是一種按照一定的規則,自動地抓取萬維網信息的程序或者腳本。

2.為什么使用爬蟲

一般需要人工處理的大量重復性的勞動很耗時費力,這樣重復性,無意義的事情可以交給爬蟲去做,好處是:
1. 減少了大量的人工操作,避免重復勞動;
2. 減少了給人主觀因素對數據篩選,取舍不當造成的影響;
3. 減少了個人因為疲勞導致的異常錯誤或者疏漏;

3.爬蟲需要了解哪些知識

3.1 網絡請求

  1. URL
  2. 請求方法(POST, GET)
  3. 請求包headers
  4. 請求包內容
  5. 返回包headers

3.2 數據解析

1. 非結構化數據
   1.1 HTML文本(包含JavaScript代碼)
   1.2 一段文本
  這里可以采用beautifulSoup4,xpath等去方式解析;
2. 結構化數據
    類似JSON格式的字符串,直接解析JSON數據就可以了,提取JSON的關鍵字段即可。

4.如何實現簡單的數據爬取

4.1 分析頁面類型和結構

通過點擊頁面鏈接和查看瀏覽器調試器Network選項可知道數據類型是通過ajax返回還是通過頁面跳轉然后渲染頁面的形式;

4.2 頁面的數據分析

這里的數據分析是我們要對接口數據的測試,模擬真正的接口調用參數,因為我們不知道真正的接口參數都包含那些,數據有沒有經過加密或者特殊轉義處理之類的,所以這一步還是去分析測試;

4.3 模擬測試接口

游戲規則:
用戶通過點擊頁面按鈕,共計5種方式:開始,是,不是,不知道,再來一局;每次只能選擇一種方式點擊,至少要點擊10次機會,最多15次機會完成一輪數據,接著進入下一輪;
這里我們需要模擬測試的數據,結構和參數大致如下:

 var text = u"開始";
 var data = {
   "content": {
     "text": text,   //純文本
     "imageUrl": ""  //微信端支持圖片輸入,pc端暫不考慮這種情況,暫且先默認為空
   }
 };

這里接口支持了post方式獲取數據,下面我采用了ajax方式獲取,這里不需要考慮跨域問題,因為我們就是下他的域名之下爬取數據,很容易跳過了瀏覽器的一些限定,當然后臺獲取還是要考慮的;

 $.ajax({
     url: 'http://webapps.msxiaobing.com/api/simplechat/getresponse?workflow=Q20',
     type: 'post',
     data: data,
     success: function(res){
         console.log(res);
         //自己的數據過濾存儲處理
     }
 });

我們只需要打開瀏覽器調試模式,在console輸入框粘貼我們的代碼,敲回車就好了;

模擬請求.png

返回的結果:


結果.png
    網頁地址:("http://webapps.msxiaobing.com/MindReader/")
    返回的參數:
    [
      { 
        Content: {
          Avatar : "/Images/chat/xiaoice_avatar.png",
          ContentType : 1,
          Text :  "那么,我就開始提問了,哼哼~聽好,第一個問題是 ——他是虛擬的嗎?",  //純文本答案
          Metadata : {
            AnswerFeed :  "Q20GameH5",
            Page.Share.Desc: "快跑啊 [掩面]!我被人工智能完爆了。。。快來救我!",
            Page.Share.Title: "人工智能讀心術:后怕!你心里想的人竟能被微軟小冰輕松猜到",
            //下面的UI是下一條問題的按鈕,每個答案返回的不一樣,可以以此作為參考一條完成答案是否結束
            UI.ButtonID.no: {   //按鈕(不是)相關信息
              displayText: "\u4e0d\u662f", 
              replyText: "\u4e0d\u662f",
              actionMeta: {}
            },
            UI.ButtonID.notsure:{  //按鈕(不確定)相關信息
              displayText: "\u4e0d\u77e5\u9053",
              replyText: "\u4e0d\u77e5\u9053", 
              actionMeta: {}
          },
          UI.ButtonID.yes:{ //按鈕(是)相關信息
              displayText: "\u662f",
              replyText: "\u662f", 
              actionMeta": {}
          },
          UI.ButtonIDList: ["UI.ButtonID.yes", "UI.ButtonID.notsure", "UI.ButtonID.no"]  //按鈕相關列表
          },
          ThumbnailUrl : null,
          VideoUrl : null,  //視頻鏈接
        },
      DelayMilliseconds:  0   //每條答案顯示延遲時間,單個答案默認為0,多個答案之間一次返回,延遲加載,給用戶感覺是多次返回,給人感覺機器人很智能
     }
  ]

返回參數說明:
    1. 整體是返回的一個數組,因為里面有的是多個答案的情況;
    2. 針對每個答案內容也有區別,有的是圖片,有的是文字;
    3. 數據是所有的數據,可能對你不一定全部有用,個人根據需要進行取舍;

到這里,我們基本的爬蟲獲取數據就說完了,接下來就是數據的過濾和存儲了。

5.數據的過濾和存儲

5.1 過濾:

數據的過濾頁腳數據的清洗,是把數據按照我們自己定制的數據結構來進行整合的過程,每個項目中數據的格式可能不一樣,跟人根據實際情況去過濾,不需要的可以舍棄;

5.2 數據的存儲:

5.2.1 數據庫存儲;
    目前比較通用的數據庫有mysql,mongodb,redis等,大數據方向熟悉的可以使用hadoop,hdfs等方式;
5.2.2 本地文件存儲:
    為了考慮安全性,javascript禁止讀寫本地文件,這樣的好處是防止通過網頁腳本修改用戶本地文件;
    所以在這里我們需要自己去寫后臺的腳本去讀寫本地文件,對nodejs,python,java不懂的去想想別的辦法,我后臺采用了nodejs和Python兩種方式實現了讀寫功能;

總結:

上面通過測試抓取微軟小冰讀心術數據抓取和過濾及存儲,也包含也跟爬蟲相關的一些基本的概念,真正的爬蟲需要在后臺去做更好,速度也更快一些,沒有技術的限制,相對比較復雜;
前端有些限制是比較棘手的,更詳盡的關于爬蟲的信息可以找我,也可以找度娘問問;
最后我這邊貼出用Python實現的完整的數據爬取及存儲的源碼,里面考慮到了反爬機制,爬取結果實時的日志統計,方便查看爬蟲的進度,選用的方式是本地文件存儲;
這里我沒有采用現有的scrapy框架去做,而是自己通過requests等實現了爬蟲的整個抓取存儲過程,數據完全自己解析,不完善的地方還請大家批評指正,個人也可根據自己情況作參考:
## Python 實現微軟小冰讀心術數據抓取和存儲
# -*- coding:utf8 -*-
import requests
import json
import random
import time
import sys
sys.setrecursionlimit(100000000)

number = 0
fileName = 'F:\\python\\duxinshu\\data\\dxs1.txt'
logfile = 'F:\\python\\duxinshu\\log.txt'

def GetCode(num, butStr=None):
    print "運行次數為:", num+1
    #發送的數據
    params1 = {"senderId": "1c5e0e31-da20-48a5-1161-0f6edcfc8d6d", "content": {"text": u"玩", "imageUrl": "", "metadata": {"Q20H5Enter": "true"}}}
    text2 = ''

    if(butStr == 1):
        text2 = u"不是"
    elif(butStr == 2):
        text2 = u"是"
    elif(butStr == 3):
        text2 = u"不知道"
    elif(butStr == 4):
        text2 = u"開始"
    elif(butStr == 5):
        text2 = u"再來一局"

    params2 = {"senderId": "1c5e0e31-da20-48a5-1161-0f6edcfc8d6d", "content": {"text": text2, "imageUrl": ""}}

    #http請求頭
    headers1 = {
        "Accept": "*/*",
        "Accept-Language": "zh-Cn,zh;q=0.8",
        "Accept-Encoding": "gzip, deflate",
        "Contention": "keep-alive",
        "Cache-Control": "max-age=0",
        "Content-length": "123",
        "Content-Type": "application/json",
        "Cookie": "ai_user=ZDqgj|2016-03-03T01:19:59.052Z; cpid=YDMiTV62QDJeSlC2f7FRSMi0ELLjNNowIU0-s1g1KEpJAA; salt=CE134ACD710FBFD79D26F94B69B8CE1E; ARRAffinity=156a6969786353112179d7a168f62f80d2aa2be36d566a73987a623c804e2516",
        "Host": "webapps.msxiaobing.com",
        "Origin": "http://webapps.msxiaobing.com",
        "Referer": "http://webapps.msxiaobing.com/MindReader",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
        "X-Requested-With": "XMLHttpRequest"
    }

    #http請求頭
    headers2 = {
        "Accept": "*/*",
        "Accept-Language": "zh-Cn,zh;q=0.8",
        "Accept-Encoding": "gzip, deflate",
        "Contention": "keep-alive",
        # "Cache-Control": "max-age=0",
        "Content-length": "93",
        "Content-Type": "application/json",
        "Cookie": "ai_user=ZDqgj|2016-03-03T01:19:59.052Z; cpid=YDMiTV62QDJeSlC2f7FRSMi0ELLjNNowIU0-s1g1KEpJAA; salt=CE134ACD710FBFD79D26F94B69B8CE1E; ARRAffinity=156a6969786353112179d7a168f62f80d2aa2be36d566a73987a623c804e2516",
        "Host": "webapps.msxiaobing.com",
        "Origin": "http://webapps.msxiaobing.com",
        "Referer": "http://webapps.msxiaobing.com/MindReader",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
        "X-Requested-With": "XMLHttpRequest"
    }

    if num == 0:
        params = params1
        headers = headers1
    else:
        params = params2
        headers = headers2
    sendData = params

    params = json.dumps(params)
    # print "發送的數據是:", params

    #請求地址
    url = 'http://webapps.msxiaobing.com/api/simplechat/getresponse?workflow=Q20'
    #發送請求
    response = requests.post(url, data=params, headers=headers)
    #獲取返回數據
    text = response.text
    #計算次數
    num += 1
    try:
        #一條答案結束添加一個換行回車
        if(butStr == 5):
            dText = u"\n" + u" 第%s條答案結束" % (number+1)
            print u" 第%s條答案結束" % (number+1)
            fileHandle = open(fileName, 'a')
            fileHandle.write(dText.encode("utf-8") + '\r\n')
            fileHandle.close()

            #記錄日志查看當前完成的條數 logfile
            fileHandle = open(logfile, 'a')
            fileHandle.write(dText.encode("utf-8") + '\n')
            fileHandle.close()

            number += 1
            global number
            if number > 5:
                number = 0
            number = number

            #讓程序暫停幾秒鐘,防止被封掉ip
            pauseTime = random.choice([3, 4, 5, 6, 7])
            time.sleep(pauseTime)

            if(number%1000 == 0):
                fileName = 'F:\\python\\duxinshu\\data\\dxs%s.txt' % (number/1000 + 1)
                global fileName
                fileName = fileName
        # print "fileName", fileName

        dict_mid = json.loads(text)

        for i in dict_mid:
            i["content"]["answer"] = sendData["content"]["text"]

        text1 = json.dumps(dict_mid, ensure_ascii=False)

        #正常存儲文件
        fileHandle = open(fileName, 'a')
        # fileHandle.write(text.encode("utf-8") + '\n')
        fileHandle.write(text1.encode("utf-8") + '\n')
        fileHandle.close()

        if(dict_mid[0] and dict_mid[0]["content"] and dict_mid[0]["content"]["metadata"]):
            dictButton = dict_mid[0]["content"]["metadata"]
        else:
            dictButton = []

        nextButton = []
        for i in dictButton:
            if(i == "UI.ButtonID.no"):
                nextButton.append(1)
            elif(i == "UI.ButtonID.yes"):
                nextButton.append(2)
            # elif(i == "UI.ButtonID.notsure"):
            #     nextButton.append(3)
            elif(i == "UI.ButtonID.Start"):
                nextButton.append(4)
            elif(i == "UI.ButtonID.again"):
                nextButton.append(5)
            elif(i == "UI.ButtonID.ok"):
                nextButton.append(2)
        butStr = random.choice(nextButton)

        if(text):
             GetCode(num, butStr)
    except Exception, e:
        print "error", e

def getDXSdata():
    GetCode(0)

if __name__ == "__main__":
    getDXSdata()

————
前端·小龍
紙上學來終覺淺,絕知此事要躬行

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容