一只爬虫太慢,那就来一群吧

一只爬虫太慢,那就来一群吧

标签: python 爬虫


多线程爬虫

#导入模块
import urllib.request as req       
import re                                                       
import time                                                   
import sqlite3 as sql                                      
import threading                                            
from queue import Queue                             

#定义全局变量,对爬到的数据计数
count = 0                         

#创建一个自定义类,继承Thread类
class GetThred(threading.Thread):             
    #类初始化
    def __init__(self, queue, url, pattern):     
        threading.Thread.__init__(self)
        self.queue = queue
        self.url = url
        self.pattern = pattern

    #重写Tread类的run方法,取出队列中的url
    def run(self):                                       
        while True:
            if not self.queue.empty():
                lists = self.queue.get()
                work(self.url, lists, self.pattern) #做爬虫该做的工作      
                self.queue.task_done()
            else:
                break


#定义爬虫如何工作
def work(url, lists, pattern):                          
    global count
    con = sql.connect('filename.db')              #连接数据库
    cur = con.cursor()                            #获得游标
    try:
        html_i = getHtml(url + lists[0])          #爬取网站内容
        lists_every = getLists(html_i, pattern)   #解析网页,获得需要的信息
        author = lists[1]
        for i in lists_every[0:3]:
            dates = i[2].split(' ')[0]
            times = i[2].split(" ")[1]
            if dates == time.strftime('%Y-%m-%d'): #丢弃过期数据,当天数据入库
                cur.execute('INSERT INTO blogdata VALUES (?,?,?,?,?)', (url + i[0], i[1], dates, times, author))
                print(lists[1] + ':' + i[1] + ' 获取成功!')
                count += 1
    except Exception as e:
        print("出现错误:\n",e)
    finally:
    cur.close()                                   #关闭游标
    con.commit()                                  #提交
    con.close()                                   #关闭数据库连接

#定义如何爬取网页
def getHtml(url):                                           
    header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1',
                     'Referer': '******'}
    req.addinfourl(fp=None, headers=header, url=url)
    request = req.urlopen(url)
    text = request.read().decode('utf-8')
    time.sleep(0.01)
    return text


#定义解析网页,提取信息,关键是合理使用正则表达式
def getLists(html, pattern):                          
    lists = re.findall(pattern, html)
    return lists


#主程序
def main():                                                 
    url = "http://blog.example.com/"             #没错,哥爬的是一个博客网站
    pattern = re.compile(r'
  • (.*?)
  • '
    , re.S) pattern2 = re.compile(r'(.*?).*?>\((.*?)\)',re.S) html = getHtml(url + 'hotbloger.html') lists = getLists(html, pattern) queue = Queue() #实例化一个队列 for q in lists: #将url加入队列 queue.put(q) for i in range(20): #一狠心放出了20条爬虫 d = GetThred(queue, url, pattern2) d.setDaemon(True) d.start() queue.join() if __name__ == "__main__": start = time.time() #计时开始 main() end = time.time() m, s = divmod(end - start, 60) #百度到转换时间的方法,毫不犹豫借用了 h, m = divmod(m, 60) print('本次爬虫共爬取到', count, '条记录') print('任务完成,共耗时%02d小时%02d分%02d秒' % (h, m, s))

    小结:实测某博客网站,作者8000人左右,只爬每位作者最新3篇文章的标题和发表时间,共2万多条信息,对比日期后每次写入数据库500条左右。单线程工作时,全部爬完一遍,需要50分钟到1小时;多线程工作时,一般在3—4分钟收工。尽管因为GIL机制,发挥不了多核CPU的优势,但对于爬虫这种主要耗时在网络请求(IO密集型)的任务,多线程效率明显高得多。
    另:qq空间的排版真是个坑,说好的严格缩进呢......
    

    你可能感兴趣的:(python)