標籤:pymysql pre col 包含 連結 錯誤 iter type ams
首先確定要爬取的笑話網站,我是直接百度笑話搜到的第一個網站,網址是http://www.jokeji.cn/,點進去發現網頁構建在我看來還是比較複雜的,由於還是初學者,首先得先找到網頁資源集中所在,找出其中的規律,然後才好有針對性的爬取資源。對於這個網址,我發現在左邊側欄有一個笑話大全的分類框。這個看起來基本上包括了全站的文字笑話了。在這個分類框下有許多小的分類,點進小的分類後是此分類下的所有笑話網頁列表,每個網頁裡麵包含一些笑話,我們最終是要把這一個一個網頁裡的笑話爬取儲存起來。
爬取思路:爬取http://www.jokeji.cn/,得到一個html頁面,分析此html頁面,獲得分類框裡的所有分類的url地址,遍曆每一個分類的url,爬取分類url的html網頁,分析分類url網頁,得到全部笑話網頁列表,遍曆笑話網頁列表url,得到最終的包含一個一個笑話的html頁面,擷取笑話,儲存到mysql資料庫。
爬取我用的是Google瀏覽器,在這個網站下按F12就可以看到網頁原始碼了,此時要分析這個笑話大全的分類框的結構,以便使用pythonRegex擷取到我們想要的資訊。
一般篩選內容都會選擇目標內容組件的上層容易唯一標識的組件,在這裡我選擇了<div class=”joketype l_left”></div>這個html,這個div可以包含所有分類的內容,然後再進行一次篩選就可以把所有url篩選出來了。到了分類子頁面我看了一下url的規律,這個分類的url都是/listXX_1.htm開始,發現分類頁面裡面有個尾頁的按鈕的url剛好是結束,並且url的.htm前面的那個數字遞增,所以就很好爬取所有笑話頁面了,至於提取笑話就不再多說了,直接上所有代碼。
mysql資料庫儲存模組代碼,檔案名稱為mysql.py。
import pymysqldef 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 urllibfrom urllib import requestimport reimport chardetimport mysqlimport 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發現很難用,還是用網頁寫好一點。
Python爬取笑話儲存在mysql裡