1. 程式人生 > >多線程版爬取故事網

多線程版爬取故事網

實現 exe don comm value obj nco result nic

  • 前言:
    為了能以更高效的速度爬取,嘗試采用了多線程
    本博客參照代碼及PROJECT來源:http://kexue.fm/archives/4385/

  • 源代碼:
     1 #! -*- coding:utf-8 -*-
     2 import requests as rq
     3 import re
     4 import time
     5 import datetime
     6 import pymysql
     7 from multiprocessing.dummy import Pool,Queue #dummy子庫是多線程庫
     8 import html
     9 from urllib.request import
    urlopen 10 from bs4 import BeautifulSoup 11 unescape = html.unescape #用來實現對HTML字符的轉移 12 13 tasks = Queue() #鏈接隊列 14 tasks_pass = set() #已隊列過的鏈接 15 results = {} #結果變量 16 count = 0 #爬取頁面總數 17 tasks.put(/index.html) #把主頁加入到鏈接隊列 18 tasks_pass.add(/index.html) #把主頁加入到已隊列鏈接 19 20 def main(tasks): 21 global
    results,count,tasks_pass #多線程可以很輕松地共享變量 22 while True: 23 url = tasks.get() #取出一個鏈接 24 url = http://wap.xigushi.com+url 25 html = urlopen(url) 26 bsObj = BeautifulSoup(html.read(), "lxml") 27 if (bsObj.meta.attrs[charset]==gb2312): 28 web = rq.get(url).content.decode(
    gbk) # 這裏的編碼要看實際情形而定 29 else: 30 web = rq.get(url).content.decode(utf8) # 這裏的編碼要看實際情形而定 31 32 urls = re.findall(href="(/.*?)", web) #查找所有站內鏈接 33 for u in urls: 34 if (u not in tasks_pass): #把還沒有隊列過的鏈接加入隊列 35 if ((re.search(images, url)) is None): 36 tasks.put(u) 37 tasks_pass.add(u) 38 else: 39 print(u, ---------------------------skipping--------------------------------------------) 40 else: 41 pass 42 43 text = bsObj.title.get_text() 44 print(datetime.datetime.now(), , url, , text) 45 db = pymysql.connect("localhost", "testuser", "test123", "TESTDB", charset=gbk) 46 dbc = db.cursor() 47 sql = "insert ignore into data1(url,title) values(%s,%s);" 48 data = (url, text) 49 dbc.execute(sql, data) 50 dbc.close() 51 db.commit() 52 db.close() 53 count += 1 54 if count % 100 == 0: 55 print(u%s done.%count) 56 57 pool = Pool(10, main, (tasks,)) #多線程爬取,4是線程數 58 total = 0 59 while True: #這部分代碼的意思是如果20秒內沒有動靜,那就結束腳本 60 time.sleep(60) 61 if len(tasks_pass) > total: 62 total = len(tasks_pass) 63 else: 64 break 65 66 pool.terminate() 67 print("terminated normally")


  • BUG:
  1. 數據庫並發寫入:
    解答來源:https://stackoverflow.com/questions/6650940/interfaceerror-0
    通過將遊標的創建移入線程,並在線程內關閉,跑出來的結果比之前好一些,但奇怪的是多幾行還是會出現並發報錯,奇怪,還能錯一半的?猜測將連接也放入線程會好些,或者幹脆不用commit提交?結果是不用commit都沒有寫入數據庫...我以為開啟了自動提交呢...
    已解決,將數據庫連接和遊標都放在線程內創建
  2. 神奇地跳過一些數據庫裏面沒有的鏈接:
    原來是過濾問題...水平真是...
    已解決,修改URL過濾方式
  3. 編碼問題真是頭都大了...
    encoding error : input conversion failed due to input error, bytes 0xB1 0x80 0xB5 0xC4

    為什麽改了那麽多次還有...顯然是gbk轉utf8問題,可是我判斷了啊,還是有些網頁就是比較亂...

  4. 又是編碼問題:
    UnicodeEncodeError: gbk codec cant encode character \u30fb in position 86: illegal multibyte sequence

  5. 網絡錯誤:
    urllib.error.HTTPError: HTTP Error 503: Forwarding failure

多線程版爬取故事網