Python爬取笑話存儲在mysql里

来源:https://www.cnblogs.com/tanjianyong/archive/2018/08/17/9495591.html
-Advertisement-
Play Games

首先確定要爬取的笑話網站,我是直接百度笑話搜到的第一個網站,網址是http://www.jokeji.cn/,點進去發現網頁構建在我看來還是比較複雜的,由於還是初學者,首先得先找到網頁資源集中所在,找出其中的規律,然後才好有針對性的爬取資源。對於這個網址,我發現在左邊側欄有一個笑話大全的分類框。這個 ...


  首先確定要爬取的笑話網站,我是直接百度笑話搜到的第一個網站,網址是http://www.jokeji.cn/,點進去發現網頁構建在我看來還是比較複雜的,由於還是初學者,首先得先找到網頁資源集中所在,找出其中的規律,然後才好有針對性的爬取資源。對於這個網址,我發現在左邊側欄有一個笑話大全的分類框。這個看起來基本上包括了全站的文字笑話了。在這個分類框下有許多小的分類,點進小的分類後是此分類下的所有笑話網頁列表,每個網頁裡面包含一些笑話,我們最終是要把這一個一個網頁里的笑話爬取存儲起來。

  爬取思路:爬取http://www.jokeji.cn/,得到一個html頁面,分析此html頁面,獲得分類框里的所有分類的url地址,遍歷每一個分類的url,爬取分類url的html網頁,分析分類url網頁,得到全部笑話網頁列表,遍歷笑話網頁列表url,得到最終的包含一個一個笑話的html頁面,獲取笑話,存儲到mysql資料庫。

  爬取我用的是Google瀏覽器,在這個網站下按F12就可以看到網頁源代碼了,此時要分析這個笑話大全的分類框的結構,以便使用python正則表達式獲取到我們想要的信息。

  一般篩選內容都會選擇目標內容組件的上層容易唯一標識的組件,在這裡我選擇了<div class=”joketype l_left”></div>這個html,這個div可以包含所有分類的內容,然後再進行一次篩選就可以把所有url篩選出來了。到了分類子頁面我看了一下url的規律,這個分類的url都是/listXX_1.htm開始,發現分類頁面裡面有個尾頁的按鈕的url剛好是結束,並且url的.htm前面的那個數字遞增,所以就很好爬取所有笑話頁面了,至於提取笑話就不再多說了,直接上所有代碼。

  mysql資料庫存儲模塊代碼,文件名為mysql.py。

import pymysql

def insert(joke):
    #獲取鏈接
    conn=pymysql.connect(host='127.0.0.1',user='root',passwd='123456',db='python')
    cur=conn.cursor()
    #sql語句,%s是占位符(%s是唯一的,不論什麼數據類型都使用%s)防止sql註入
    sql='insert into joke(joke) VALUES(%s)'
    #params=('eric','wuhan') #參數 插入單條
    #li=[('a1','b1'),('a2','b2')] #批量插入參數
    #reCount=cur.execute(sql,params)
    reCount=cur.executemany(sql,joke) #批量插入
    conn.commit() #提交,執行多條命令只需要commit一次就可以
    cur.close()
    conn.close()

def get_one():
    #獲取鏈接
    conn=pymysql.connect(host='127.0.0.1',user='root',passwd='123456',db='python')
    cur=conn.cursor()
    sql1='select number from number'
    reCount=cur.execute(sql1)
    number=cur.fetchone()[0]+1
    sql2='select joke from joke where id=%s'
    reCount=cur.execute(sql2,number)
    joke=cur.fetchone()[0]
    sql3='update number set number=%s where number=%s'
    params=(number,number-1)
    reCount=cur.execute(sql3,params)
    conn.commit()
    cur.close()
    conn.close()

註意:pymysql模塊是需要安裝的,一般現在python都預設有pip包管理,沒有這個模塊直接在命令行執行:pip pymysql即可。需事先在mysql資料庫里創建python資料庫,表joke,表有兩列,一列是id,我設置其為int類型的自增的主鍵屬性,一列joke,設置為text類型,存放笑話。insert函數是傳入一個joke的tuple類型參數,這個tuple裡面存放是一條一條字元串,每條字元串表示一個笑話,insert函數的功能是將這個tuple元組的笑話插入到資料庫。get_one函數是得到一條笑話,在這裡我添加一個表專門來保存笑話取到哪了,以免讀取重覆笑話,這個表名字是number,裡面有一個欄位,number,我實現插入了一條記錄,值為0。

  爬蟲代碼,文件名為spider.py。

import urllib
from urllib import request
import re
import chardet
import mysql
import time
'''
找到http://www.jokeji.cn/list29_1.htm笑話列表
獲取第一個笑話網頁http://www.jokeji.cn/jokehtml/bxnn/2018080417455037.htm
遍歷完所有笑話網頁
獲取下一個笑話列表,重覆遍歷,直至此分類笑話遍歷完
遍歷下一個分類
'''
class Spider():
    url='http://www.jokeji.cn/jokehtml/bxnn/2018073023294432.htm'
    header = {
        'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36',
        'Accept-Encoding': '',
      'Referer':'http://www.jokeji.cn/list29_1.htm'
    }
    classifys=[] #list集合,存儲笑話分類url

    #獲取html文本
    def __fetch_content(self):
        cookie_html = request.Request(Spider.url,headers=Spider.header)
        cookie_html = request.urlopen(cookie_html)
        htmls=cookie_html.read()
        #使用chardet獲取到htmls的編碼格式
        encoding=chardet.detect(htmls)
        encoding=encoding['encoding']
        #不加ignore的時候總是出現字元轉換錯誤,說明有非法字元,必須加上ignore忽略非法字元
        htmls=htmls.decode(encoding,'ignore')
        time.sleep(0.1)
        return htmls
    
    #獲取笑話分類url
    def __analysis_classify(self):
        Spider.url='http://www.jokeji.cn/'
        Spider.header['Referer']='http://www.jokeji.cn/'
        htmls=self.__fetch_content()
        root_pattern='<div class="joketype l_left">([\s\S]*?)</div>'
        classify_pattern='<a href="([\s\S]*?)">'
        root_html=re.findall(root_pattern,htmls)
        Spider.classifys=re.findall(classify_pattern,str(root_html))
        
    #獲取當前頁面里的所有笑話,返回一個tuple
    def __analysis(self,htmls):
        anchors=[]
        root_pattern='<span id="text110">([\s\S]*?)</span>'
        juck_pattern='<P>\d、([\s\S]*?)</P>'
        root_html=re.findall(root_pattern,htmls)
        for html in root_html:
            jucks=re.findall(juck_pattern,html)
            #替換換行符
            c=re.compile('<[b|B][r|R]\s*/*>')
            for i in jucks:
                i=c.sub('\n',i)
                anchors.append(i)
                #i=i.replace('<BR>','\n')
            return anchors
        return anchors
    #爬取原創笑話
    def __analysis_yuanchuangxiaohua(self,url):
        url='http://www.jokeji.cn'+url
        pass
        
    #爬取分類下的笑話
    def __analysis_joke(self):
        Spider.header['Referer']='http://www.jokeji.cn/'
        root_pattern='<div class="list_title">([\s\S]*?)</div>'
        page_pattern='<a href="([\s\S]*?)"\s*target="_blank"\s*>'
        for classify in Spider.classifys:
            try:
                if '/yuanchuangxiaohua' in classify:
                    self.__analysis_yuanchuangxiaohua(classify)
                classify='http://www.jokeji.cn'+classify
                Spider.url=classify
                htmls=self.__fetch_content()
                #記錄分類裡面最大頁面數           
                max_number=int(re.findall('[\s\S]*?(\d*?)\.htm">尾頁</a>',htmls)[0])
                #開始遍歷每一大頁,一大頁包含很多小頁面,小頁面裡面才是笑話
            except BaseException:
                continue
            for bigpage_number in range(1,max_number+1):
                try:
                    bigpage_url=classify
                    temp=re.compile('(\d*).htm')
                    #更改url,因為分類下每一大頁都是有規律的,都是.htm前面的數字從1加到最大頁面數
                    bigpage_url=temp.sub(str(bigpage_number)+'.htm',bigpage_url)
                    #替換url
                    Spider.url=bigpage_url
                    htmls=self.__fetch_content()
                    root_html=re.findall(root_pattern,htmls)
                    #獲取一大頁裡面的小頁面的url地址
                    pages=re.findall(page_pattern,root_html[0])
                    #遍歷所有小頁面url,獲取其中的笑話
                except BaseException:
                    continue
                for page in pages:
                    try:
                        Spider.url='http://www.jokeji.cn'+page
                        htmls=self.__fetch_content()
                        tuples=self.__analysis(htmls)
                        #插入到資料庫
                        mysql.insert(tuples)
                    except BaseException:
                        continue


    def go(self):
        self.__analysis_classify()
        self.__analysis_joke()

spider=Spider()
spider.go()

由於笑話分類里的原創笑話的頁面格式不同,所以就差這個還沒實現。初學,第一次寫博客記錄,下載了編寫博客的openLiveWriter發現很難用,還是用網頁寫好一點。

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 我們都知道平常在使用SpringBoot和SpringCloud的時候,如果需要載入一兩個配置文件的話我們通常使用@Value("${屬性名稱}")註解去載入。但是如果配置文件屬性特別多的時候使用這種方式就顯得特別的不友好了。 比如說,我們要載入下方這個名為application.yml的配置文件。 ...
  • 我在知乎上看到一個形象解釋的例子: 個人理解:將具體業務和底層邏輯解耦的組件。 大致的效果是:需要利用服務的人(前端寫業務的),不需要知道底層邏輯(提供服務的)的具體實現,只要拿著中間件結果來用就好了。 舉個例子:我開了一家炸雞店(業務端),然而周邊有太多屠雞場(底層),為了成本我肯定想一個個比價, ...
  • 前幾天和同事聊天,同事說: “業務的服務(相對於我們基礎架構這邊的底層技術)在技術上就需要解決三個問題:分散式、通信和存儲。” 我回憶之前做業務的時光,覺得確實,再加上一個“服務治理”就差不多了。想想“服務設計要解決的問題”這個話題可以把之前靜兒寫的很多文章做一個歸納概括。今天做一個總結。 分散式 ...
  • 適配器模式在軟體開發界使用及其廣泛,在工業界,現實中也是屢見不鮮。比如手機充電器,筆記本充電器,廣播接收器,電視接收器等等。都是適配器。 適配器主要作用是讓本來不相容的兩個事物相容和諧的一起工作。比如, 通常我們使用的交流電都是220v,但是手機電池能夠承載的5v電壓,因此直接將我們使用的220v交 ...
  • 這段時間接觸公眾號開發,寫下向用戶發送消息模板的介面調用 先上介面代碼 15行那段getJsonByWX是統一調用微信介面的方法,每個項目都有自己的調用方法,我這裡就不貼了。介面調用鏈接:https://api.weixin.qq.com/cgi-bin/message/template/send? ...
  • 主要思路參考這篇博客的內容,把地址貼上: http://www.cnblogs.com/zhoujie/p/python18.html 下麵貼上我自己的代碼 讀取excel數據的demo代碼如下: 1 def read_excel_demo(): 2 # 打開文件 3 workbook = xlrd ...
  • const的用法,特別是用在函數後面 在普通的非 const成員函數中,this的類型是一個指向類類型的 const指針。可以改變this所指向的值,但不能改變 this所保存的地址。 在 const成員函數中,this的類型是一個指向 const類類型對象的 const指針。既不能改變 this所... ...
  • 常用排序 名稱 複雜度 說明 備註 冒泡排序Bubble Sort O(N*N) 將待排序的元素看作是豎著排列的“氣泡”,較小的元素比較輕,從而要往上浮 插入排序 Insertion sort O(N*N) 逐一取出元素,在已經排序的元素序列中從後向前掃描,放到適當的位置 起初,已經排序的元素序列為 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...