天天看點

<進擊的蟲師>如何讓程式"懂很多"?

聊聊?

最近在做一個有意思的小項目, 在一個聊天對話中, 你向電腦提出問題, 他會自動分詞,然後根據關鍵字, 自動答複你

對所有的關鍵字做出解釋, 工作量實在太大, 即使能解釋, 資料庫容量也不夠

最後, 想到了實時爬蟲...

如何分詞?

目前比較好用的分詞器 結巴(jieba)
今天早上吃了蔥油餅和豆腐腦

爬哪裡?

現成的百度百科

百度百科

爬什麼?

那要看使用者問什麼了, 爬蟲最好是實時的, 這樣就能根據使用者的提問, 直接擷取關鍵詞資料

效果示範

如何讓程式變得更聰明(優化程式)?

每次爬完一個關鍵詞後, 做一個本地備份, 既能避免百度政策臨時變更帶來的災難, 也便于根據使用者習慣, 優化程式

本地資料

爬不到怎麼辦?

對于使用者問到, 但百度百科未收錄的關鍵詞, 會自動記錄到log日志裡面,便于後期改進詞庫

log

實時爬取百度百科

import os
import sys
import requests
from lxml import etree
import re
import time

# 從本地擷取資料
def getLocalData(keyword):
    # 擷取/baikeInfo下的所有檔案名
    print("嘗試查詢本地資料資訊")
    fileNames = os.listdir('./baikeInfo/')
    # 查詢本地是否存在緩存資料
    latestCreateTime = ''
    for fileName in fileNames:
        # 檔案關鍵字
        fileName0 = fileName.split("_")[0]
        # 檔案建立時間
        fileName1 = fileName.split("_")[1].split('.')[0]
        # 如果目前檔案名與目的檔案名一緻的話
        if fileName0 == keyword:
            # 如果時間緩存變量為空, 則存儲目前時間戳
            if latestCreateTime == '':
                latestCreateTime = fileName1
            # 如果時間緩存變量不為空, 則比較時間戳, 如果目前時間更晚, 則更新時間戳
            elif int(fileName1) > int(latestCreateTime):
                latestCreateTime = fileName1
    # 建立需要讀取的檔案名
    NeedFileName = ''
    result = ''
    # 如果時間戳為空, 則說明檔案不存在
    if latestCreateTime == '':
        return "未收錄本詞條"
    else:
        NeedFileName = keyword+"_"+latestCreateTime+'.txt'
        NeedFileNamePath = './baikeInfo/'+NeedFileName
        with open(NeedFileNamePath, 'r') as f:
            result = f.read()

    return result

# 從網絡擷取資料
def getInfo(keyword):
    headers = {
        # 設定使用者代理頭(為狼披上羊皮)
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
    }
    target_url = "https://baike.baidu.com/item/"+ str(keyword)
    result = ""

    try:
        # 嘗試驅動爬蟲擷取實時資料
        try:
            data = requests.get(target_url, headers = headers)
            data_etree = etree.HTML(data.content)
            content_list = data_etree.xpath('//div[@class="lemma-summary"]/div[@class="para"]')
            # 如果不存在這個詞條
            if len(content_list) == 0:
                return "未收錄本詞條"
            for content in content_list:
                # 遞歸抽取子節點資料
                result +=content.xpath('string(.)')
        # 如果無法擷取響應資料, 則嘗試讀取本地資料, 做出響應
        except Exception as e:
            result = getLocalData(keyword)
            return result
    # 如果本地沒有資料, 也無法從網際網路擷取, 則傳回未收錄詞條
    except Exception as e:
        result = "未收錄本詞條"
        return result
    # 資料清洗, 移除類似[1][2]之類的标記字元
    result_list, num = [r for r in re.subn(r'\[\d{0,3}\]', '', result)]
    # 資料清洗, 移除多餘的空格字元
    result = ''
    for r in result_list:
        result += str(r).strip()
    return result

# 儲存資料, 并通過log記錄未收錄的的詞條
def saveData(fileName, info):
    # 記錄使用者未查找到的詞條, 結束函數
    if info == "未收錄本詞條":
        if os.path.exists("./log/"):
            pass
        else:
            os.makedirs("./log/")
        with open("./log/log.txt", "a") as f:
            newlog = time.strftime("%Y年%m月%d日%H時%M分%S秒")+"  "+"未找到關鍵詞:"+fileName+"\n"
            f.write(newlog)
            return

    # 嘗試建立baikeInfo檔案夾    
    if os.path.exists("./baikeInfo/"):
        pass
    else:
        os.makedirs("./baikeInfo/")
    # 擷取目前的年月日時分秒
    # 将資料儲存到baikeInfo中, fileName.txt
    file_path = "./baikeInfo/" + fileName +"_"+ time.strftime("%Y%m%d%H%M%S") +'.txt'
    # 存儲資料
    with open(file_path, "w+") as f:
        f.write(info)

# 程式入口
def getInput():
    wd = ''
    try: 
        wd = sys.argv[1]
    except:
        wd = "人工智能"
    result = getInfo(wd)
    if len(result)>0:
        saveData(wd,result)
    print(result)
    if result == "未收錄本詞條":
        return False
    return result

def main():
    result = getInput()
    return result

if __name__ == '__main__':
    main()
           

為程式加入彩蛋?

彩蛋很容易加, 可以先寫好一個字典, 裡面放入一些關鍵詞, 并放入彩蛋, 當分詞器得到使用者關鍵詞時,先查字典, 如果能比對到彩蛋, 就在最終的結果裡面加入彩蛋資訊,

本篇文章彩蛋:

文章點贊過50, 作者會上線程式的彩蛋版本,并将彩蛋連結更新到文章底部!