緣起:
上篇因為工作需要(就是把騰訊新聞copy到單位自己網站上去每天15條更新)所以寫了一個抓取騰訊新聞的python小腳本
這次是因為想用手機看youku視頻,比如xiaoy的魔獸解說,但是打開瀏覽器輸入game.youku.com的時候,三星9003太不
給力,因而需要一個打開速度快的目錄小網站。
思路:
1.數據表設計:
id(int), //主鍵自增
title(varchar 50), //速度優先,只需要title,不需要圖片
href(varchar 50), //視頻播放地址
date(varchar 25), //采集的date中有如“1小時前”,因此也設計成varchar
2.采集函數設計:
視頻列表頁url = http://i.youku.com/u/UMTE0NDEzOTky/videos/order_1_view_1_page_id (id =1,2...)
每頁視頻個數為20,采集內容為title,href,date,優酷的html很規整,因此正則提取很好寫,詳見代碼。
3.采集流程及入庫:
采用多線程采集,開9個進程,每個進程提取一個列表頁20個視頻,總共采集180個視頻,如果想全站采集的話修改即可。
數據庫采用mysql,如何使python支持mysql詳見Python網站建設,因為是多線程所以在插入數據的時候需要資源鎖。
關於python多線程thread以及資源鎖,可以參照Python模塊學習。
代碼:
1 #!/usr/bin/env python 2 #coding=utf-8 3 import urllib2 4 import re 5 import MySQLdb 6 import thread 7 import time 8 #創建鎖,用於訪問數據庫 9 lock = thread.allocate_lock() 10 #抓取函數 11 def fetch(id=1,debug=False): 12 urlbase = 'http://i.youku.com/u/UMTE0NDEzOTky/videos/' 13 url = urlbase + 'order_1_view_1_page_' + str(id) + '/' 14 res = urllib2.urlopen(url).read() 15 abstarct = re.compile(r'<ul class="v".*?</ul>',re.DOTALL).findall(res) 16 17 vid_list = [] 18 for i in range(0,len(abstarct)): 19 title = re.compile(r'title="(.*?)"',re.DOTALL).findall(abstarct[i]) 20 href = re.compile(r'href="(.*?)"',re.DOTALL).findall(abstarct[i]) 21 date = re.compile(r'<span>(.*?)</span>',re.DOTALL).findall(abstarct[i]) 22 if debug == True: 23 print title[0]+href[0]+date[0] 24 vid = { 25 'title' : title[0], 26 'href' : href[0], 27 'date' : date[0] 28 } 29 vid_list.append(vid) 30 #print thread.get_ident() 31 return vid_list 32 #插入數據庫 33 def insert_db(page): 34 global lock 35 #執行抓取函數 36 vid_date = fetch(page,False) 37 sql = "insert into ykgame (title,href,date) values (%s,%s,%s)" 38 #插入數據,一頁20條 39 for i in range(0,len(vid_date)): 40 param = (vid_date[i]['title'],vid_date[i]['href'], 41 vid_date[i]['date']) 42 lock.acquire() #創建鎖 43 cursor.execute(sql,param) 44 conn.commit() 45 lock.release() #釋放鎖 46 47 if __name__ == "__main__": 48 #連接數據庫 49 conn = MySQLdb.connect(host="localhost",user="root", 50 passwd="root",db="python_test",charset="utf8") 51 cursor = conn.cursor() 52 conn.select_db('python_test') 53 #創建表 54 sql = "CREATE TABLE IF NOT EXISTS \ 55 ykgame(id int PRIMARY KEY AUTO_INCREMENT, title varchar(50), \ 56 href varchar(50), date varchar(25))" 57 cursor.execute(sql) 58 #插入數據庫 59 for i in range(1,10): 60 thread.start_new_thread(insert_db,(i,)) 61 print '采集中...' 62 time.sleep(3) 63 #關閉數據庫 64 cursor.close() 65 conn.close()
說明:
urllib2模塊:進行網頁內容抓取
re模塊:進行正則表達式提取
MySQLdb模塊:mysql操作
thread模塊:多線程操作
time模塊:time.sleep(3)
遇到的問題:
1.mysql中文亂碼:問題比較復雜,通用解決辦法如下
程序中只要在開頭寫好:#coding=utf-8
連接數據庫的時候設置編碼方式:conn=MySQLdb.connect(host="127.0.0.1",user="webdb",passwd="web123",db="web",charset="utf8")
對於采集來的中文字符串,可以編碼轉換后插入str = str.decode("gbk").encode("utf-8")
2.Warning: Data truncated for column 'href' at row 1
原因:href 數據庫中為 varchar(25),而實際長度>25
解決辦法:將href 數庫中改為 varchar(50)
3.多線程問題:現象混亂有時候無報錯,注意事項如下
使用相同資源是需要用資源鎖,不然出現異常
線程處理時間短時,啟用線程后加time.sleep(3)
下篇預告:使用web.py搭建網站框架