1. 程式人生 > >樸素貝葉斯趣味挑戰項目

樸素貝葉斯趣味挑戰項目

urlopen docs mage git ins -a 自動 查看 lan

1.目的

  定時爬取笑話網站,利用樸素貝葉斯分析,將不同笑話發給不同人群。

2.方案

  (1)首先利用python爬蟲抓取某個網站上的笑話。

   (2)之後利用windows系統的任務計劃程序功能早上8點定時執行此python爬蟲。因為不可能一直開著電腦,所以用雲服務器。

   (3)然後用樸素貝葉斯模型來判斷當前的笑話是否屬於成人笑話。

   (4)如果是成人笑話,用爬蟲把它自動發給好兄弟的qq郵箱。

   (5)如果不是成人笑話,用爬蟲把它自動發給女朋友的qq郵箱。

3.實施

  1.選取合適的笑話網站。---- 某某網站。

   2.學習爬蟲,本來只會RSS源那樣子爬,但是好多網站找不到RSS地址,所以我只能學習爬蟲。

   (其實最後也沒用到抓包工具,可以先不下載)首先需要抓包工具,下載火狐瀏覽器的低版本才能兼容httpfox,下載地址http://ftp.mozilla.org/pub/firefox/releases/35.0/win32/zh-CN/,這個是中文版

   首先入門爬蟲,https://cuiqingcai.com/1052.html,學長推薦的課程,開始入門。

   這門課程上的是Python2,關於其中的函數的差別,http://blog.csdn.net/duxu24/article/details/77414298

首先以post的方式爬取一個不需要驗證碼的 

import urllib.request
import urllib.parse values = {"username":"[email protected]","password":"xxxxx"} data = urllib.parse.urlencode(values).encode(utf-8) url = "http://nian.so/" request = urllib.request.Request(url,data) response = urllib.request.urlopen(request) print(response.read())

  3.記錄一下cookie學習的代碼。

  1)利用CookieJar對象實現獲取cookie的功能,並存儲到變量中,打印變量。

import urllib.request
import urllib.parse
import urllib.error
import http.cookiejar

cookie = http.cookiejar.CookieJar() #聲明一個CookieJar對象實例來保存cookie
#使用HTTPCookieProcessor創建cookie處理器,並以其為參數構建opener對象
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
#構建請求
respoense = opener.open("http://www.baidu.com")
for item in cookie:
    print(Name = ,item.name)
    print(Value = ,item.value)

  2)保存Cookie到文件,用MozillaCookieJar模塊

import urllib.request
import urllib.parse
import urllib.error
import http.cookiejar

filename = "F:\\cookie.txt"
cookie = http.cookiejar.MozillaCookieJar(filename) #聲明一個CookieJar對象實例來保存cookie
#使用HTTPCookieProcessor創建cookie處理器,並以其為參數構建opener對象
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
#構建請求
respoense = opener.open("http://www.baidu.com")
#保存cookie到文件
cookie.save(ignore_discard=True,ignore_expires=True)

  ignore_discard的意思是即使cookies將被丟棄也將它保存下來,ignore_expires的意思是如果在該文件中cookies已經存在,則覆蓋原文件寫入。

  打開cookie文件。

  技術分享圖片

  3)從文件中獲取Cookie並訪問

import urllib.request
import http.cookiejar

filename = "F:\\cookie.txt"
cookie = http.cookiejar.MozillaCookieJar() #聲明一個CookieJar對象實例來保存cookie
#使用HTTPCookieProcessor創建cookie處理器,並以其為參數構建opener對象
cookie.load(filename,ignore_discard=True,ignore_expires=True)
request = urllib.request.Request("http://www.baidu.com")
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
#構建請求
response = opener.open(request)
print(response.readline())

   4)利用cookie模擬網站登錄

   訪問我校教務系統。

import urllib.request
import http.cookiejar

filename = "F:\\cookie.txt"
cookie = http.cookiejar.MozillaCookieJar(filename) #聲明一個CookieJar對象實例來保存cookie
#使用HTTPCookieProcessor創建cookie處理器,並以其為參數構建opener對象
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
#構建請求
loginUrl = "http://ids.chd.edu.cn/authserver/login?service=http%3A%2F%2Fportal.chd.edu.cn%2F"
values = {"username":"201524070201","password":"xxxxxx"}
data = urllib.parse.urlencode(values).encode(utf-8)
respoense = opener.open(loginUrl,data)
#保存cookie到文件
cookie.save(ignore_discard=True,ignore_expires=True)
gradeUrl = "http://bkjw.chd.edu.cn/eams/teach/grade/course/person!search.action?semesterId=75&projectType="
result = opener.open(gradeUrl)
print(result.read())

  4.記錄正則表達式學習過程中的一點小問題。

   我把學習正則的python文件命名為re.py,結果說module ‘re‘ has no attribute ‘match‘,結果一百度

   命名py腳本時,不要與python預留字,模塊名等相同,即Python文件名不要使用Python系統庫的名字,就是因為使用了Python系統庫的名字,

   所以在編譯的時候才會產生.pyc文件。正常的Python文件在編譯運行的時候是不會產生.pyc文件的!

   這類問題的解決方法則是:更改python腳本的命名,不要與python系統庫重合即可。回答鏈接:https://www.cnblogs.com/fangxx/p/xx-python02.html

  5.正式學習爬取某笑話網站。

   學習崔慶才大神的爬取記錄,還有後人更改py2為py3的博客,進行學習。

   1)目標。

    (1)抓取糗事百科熱門段子。

    (2)過濾袋有圖片的段子。

    (3)根據發布時間,段子內容,點贊數,進行篩選。

   2)確定URL並抓取頁面代碼。

import urllib.request
import urllib.error
#不需要用到cookie
#構建請求
page = 1
url = "https://www.qiushibaike.com/hot/page/" + str(page)
header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36"
}
try:
    request = urllib.request.Request(url,headers=header)
    response = urllib.request.urlopen(request)
    print(response.read().decode("utf-8"))
except urllib.error.URLError as e:
    if hasattr(e,"code"):
        print(e.code)
    if hasattr(e,"reason"):
        print(e.reason)

    提取到的內容如圖所示。

技術分享圖片

    3)加入正則表達式提取第一頁的所有段子。

      先寫正則表達式。

技術分享圖片

    正則表達式如下:

        #0發布人 1內容 2是圖片 3是點贊數
        pattern = re.compile(‘‘‘<div class="article.*?<h2>(.*?)</h2>.*?‘‘‘
                             + ‘‘‘<span>(.*?)</span>.*?‘‘‘
                             + ‘‘‘<!-- 圖片或gif -->(.*?)<div class="stats">.*?‘‘‘
                             + ‘‘‘<span class="stats-vote"><i class="number">(.*?)</i>‘‘‘, re.S)    

     正則表達式在寫的時候,一定要註意空格!!! <!-- 圖片或gif --> 裏面的空格害我找了很長時間。

   4)獲取笑話。

    過濾掉帶圖片的。

import urllib.request
import urllib.error
import re

def init():
    #不需要用到cookie
    #構建請求
    page = 1
    url = "https://www.qiushibaike.com/hot/page/" + str(page)
    header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36"
    }
    try:
        request = urllib.request.Request(url,headers=header)
        response = urllib.request.urlopen(request)
        content = response.read().decode("utf-8")
        #0發布人 1內容 2是圖片 3是點贊數
        pattern = re.compile(‘‘‘<div class="article.*?<h2>(.*?)</h2>.*?‘‘‘
                             + ‘‘‘<span>(.*?)</span>.*?‘‘‘
                             + ‘‘‘<!-- 圖片或gif -->(.*?)<div class="stats">.*?‘‘‘
                             + ‘‘‘<span class="stats-vote"><i class="number">(.*?)</i>‘‘‘, re.S)        
        items = re.findall(pattern,content)
        #只要沒圖片的段子
        for item in items:
            if not re.search("img",item[2]):
                result = re.sub(<br/>,"\n",item[1])
                print("發布人: %s\n內容:%s\n點贊數:%s\n" %(item[0].strip(),item[1].strip(),item[3].strip()))
    except urllib.error.URLError as e:
        if hasattr(e,"code"):
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)

init()
#<div class="content">

    把那種查看全文的顯示全。

技術分享圖片

    獲取段子完整代碼。其中遇到的問題:http://www.cnblogs.com/littlepear/p/8456897.html

import urllib.request
import urllib.error
import re
page = 5
url = "https://www.qiushibaike.com/hot/page/"
mainurl = "https://www.qiushibaike.com"
header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36"
    }
def init():
    content = getpage(index = page)
    #0發布人 1內容 2是圖片 3是點贊數
    pattern = re.compile(‘‘‘<div class="article.*?<h2>(.*?)</h2>.*?‘‘‘
                         + ‘‘‘<a href="(.*?)".*?‘‘‘
                         + ‘‘‘<span>(.*?)</span>.*?‘‘‘
                         + ‘‘‘<!-- 圖片或gif -->(.*?)<div class="stats">.*?‘‘‘
                         + ‘‘‘<span class="stats-vote"><i class="number">(.*?)</i>‘‘‘, re.S)        
    items = re.finditer(pattern,content)
    pageItems = []
    #只要沒圖片的段子
    for item in items:
        zannum = int(item.group(5).strip())
        if ((not re.search("img",item.group(4))) and (zannum>1000)):
            #print(zannum) 挑選贊大於1000的笑話
            #print(item.group())
            if ((not re.search("查看全文",item.group()))):
                result = re.sub("<br/>","\n",item.group(3))
                #print("發布人: %s\n內容:%s\n點贊數:%s\n" %(item.group(1).strip(),result.strip(),item.group(5).strip()))
                pageItems.append([item.group(1).strip(),result.strip(),item.group(5).strip()])
            else: 
                contentForAll = getpage(contentUrl=item.group(2))
                patternForAll = re.compile(‘‘‘<div class="article.*?<h2>(.*?)</h2>.*?‘‘‘
                    + ‘‘‘<div class="content">(.*?)</div>.*?‘‘‘
                    + ‘‘‘<span class="stats-vote"><i class="number">(.*?)</i>‘‘‘,re.S)
                # patternForAll = re.compile(‘‘‘<div class="article.*?<h2>(.*?)</h2>‘‘‘
                #                                + ‘‘‘.*?<div class="content">(.*?)</div>‘‘‘
                #                                + ‘‘‘.*?<i class="number">(.*?)</i>‘‘‘, re.S)
                newitems = re.findall(patternForAll,contentForAll)
                result = re.sub("<br/>","\n",newitems[0][1])
                #print("發布人: %s\n內容:%s\n點贊數:%s\n" %(newitems[0][0].strip(),result.strip(),newitems[0][2].strip()))
                pageItems.append([newitems[0][0].strip(),result.strip(),newitems[0][2].strip()])
    return pageItems
def getpage(index=None,contentUrl=None):
    response = None
    if index:
        request = urllib.request.Request(url + str(index),headers=header)
        response = urllib.request.urlopen(request)
    elif contentUrl:
        request = urllib.request.Request(mainurl + contentUrl,headers=header)
        response = urllib.request.urlopen(request)
    return response.read().decode("utf-8")
def main():
    pageItems = []
    pageItems = init()
    for jokelist in pageItems:
        for content in jokelist:
            print(content)
main()

    效果:

技術分享圖片

   6.通過樸素貝葉斯判斷是成人笑話還是普通笑話。

    用了一份停用表,感覺效果還很好。

    之前與之後的對比:

技術分享圖片

    關於樸素貝葉斯的寫法與推導,在之前的博客上:http://www.cnblogs.com/littlepear/p/8322251.html

    同時關於漢字的處理,參考:https://www.cnblogs.com/marc01in/p/4775440.html

   

from numpy import *

#加載停用詞
stop_word = []
def loadword(text):
    word = []
    fr = open(text,r)
    lines = fr.readlines()
    for line in lines:
        word.extend(line.strip())
    fr.close()
    return word

def bagOfWordsVec(vocabSet,inputSet):
    returnVec = [0]*len(vocabSet)
    for word in inputSet:
        if word in vocabSet:
            returnVec[vocabSet.index(word)] += 1
    return returnVec

def textParse(bigString,stop_word):
    listOfWord = []
    #print(stop_word)
    for word in bigString:
        if word not in stop_word:
            listOfWord.append(word)
    return listOfWord
    
#創建一個詞匯的集合
def createVocabList(dataSet):
    vocabSet = set([]) #創建空集合
    for document in dataSet:
        vocabSet |= set(document)
    return list(vocabSet)

def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix) #有幾行話
    numWords = len(trainMatrix[0]) #每行的詞匯表的詞數
    # print(numTrainDocs)
    # print(numWords)
    pAbusive = sum(trainCategory)/float(numTrainDocs) #p(Ci) 算是垃圾郵件的概率
    p0Num = ones(numWords)
    p1Num = ones(numWords)
    # print(p0Num)
    #p0Denom = 2.0; p1Denom = 2.0 #書上是2.0 不知道為什麽 p(x1|c1)= (n1 + 1) / (n + N)  看網上的,
    #為了湊成概率和是1,N應該是numWords
    p0Denom = 1.0*numWords; p1Denom = 1.0*numWords
    for i in range(numTrainDocs):
        if trainCategory[i] == 1: 
            #某句話是侮辱性的話
            p1Num += trainMatrix[i] #矩陣相加
            #print(p1Num)
            p1Denom += sum(trainMatrix[i])
            #print(p1Denom)
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])

    p1Vect = log(p1Num/p1Denom)
    p0Vect = log(p0Num/p0Denom)
    return p0Vect,p1Vect,pAbusive

def classifyNB(vecOClassify,p0Vec,p1Vec,p1Class):
    p1 = sum(vecOClassify*p1Vec) + log(p1Class)
    p0 = sum(vecOClassify*p0Vec) + log(1 - p1Class)
    if p1 > p0:
        return 1
    else: return 0

#進行測試
def jokeTest():
    stop_word = loadword(stopword1.txt)
    docList = [];classList = []
    for i in range(1,26):    
        text = (joke/adult/%d.txt % i)
        wordList = loadword(text)
        wordList = textParse(wordList,stop_word)
        docList.append(wordList)
        classList.append(1)
        
        text = (joke/normal/%d.txt % i)
        wordList = loadword(text)
        wordList = textParse(wordList,stop_word)
        docList.append(wordList)
        classList.append(0)
    vocabList = createVocabList(docList)
    # 40個訓練集,10個測試集
    trainingSet = list(range(50));testSet = []
    for i in range(10):
        randIndex = int(random.uniform(0, len(trainingSet)))
        testSet.append(trainingSet[randIndex]) #保證隨機性,不管重復
        del(trainingSet[randIndex]) 
    trainMax = []; trainClasses = []
    for docIndex in trainingSet:
        #print(docIndex)
        trainMax.append(bagOfWordsVec(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V,p1V,pSpam = trainNB0(array(trainMax),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:
        wordVector = bagOfWordsVec(vocabList, docList[docIndex])
        if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
            errorCount += 1
        print("the text %s \n the result %s the true result %s " % (docList[docIndex],classifyNB(array(wordVector), p0V, p1V, pSpam),classList[docIndex]))
    print("error rate: %f " % (float(errorCount)/len(testSet)))
# def main():
#     stop_word = []
#     stop_word = loadword(‘stopword.txt‘)
#     for item in stop_word:
#         print(item)
#main()
jokeTest()

    50個樣例采用交叉驗證的方法,40個訓練,10個測試,錯誤率在10%左右。

    技術分享圖片

    7.通過qq郵箱發送郵件

     參考:https://www.cnblogs.com/xshan/p/7954317.html

     

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

my_sender=[email protected]    # 發件人郵箱賬號
my_pass = xxxxxxxxx              # 發件人郵箱密碼(當時申請smtp給的口令)
my_user=[email protected]      # 收件人郵箱賬號
def mail():
    ret=True
    try:
        content = "I love you!"
        msg=MIMEText(content,plain,utf-8)
        msg[From]=formataddr(["發件人昵稱",my_sender])  # 括號裏的對應發件人郵箱昵稱、發件人郵箱賬號
        msg[To]=formataddr(["收件人昵稱",my_user])              # 括號裏的對應收件人郵箱昵稱、收件人郵箱賬號
        msg[Subject]="郵件主題-測試"                # 郵件的主題,也可以說是標題
        server=smtplib.SMTP_SSL("smtp.qq.com", 465)  # 發件人郵箱中的SMTP服務器,端口是465
        server.login(my_sender, my_pass)  # 括號中對應的是發件人郵箱賬號、郵箱密碼
        server.sendmail(my_sender,[my_user,],msg.as_string())  # 括號中對應的是發件人郵箱賬號、收件人郵箱賬號、發送郵件
        server.quit()# 關閉連接
    except Exception:# 如果 try 中的語句沒有執行,則會執行下面的 ret=False
        ret=False
    return ret

ret=mail()
if ret:
    print("郵件發送成功")
else:
    print("郵件發送失敗")

     8.整合

      所有代碼稍後給個github上的鏈接:

      以下是正常笑話:

技術分享圖片

    以下是成人笑話:

技術分享圖片

樸素貝葉斯趣味挑戰項目