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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...