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

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

标签: 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'<li><a href=".*?/([^"].*?)">(.*?)</a></li>', re.S)
    pattern2 = re.compile(r'<span class="title"><a href=".*?/(.*?)" .*?>(.*?)</a>.*?>\((.*?)\)</span>',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空间的排版真是个坑,说好的严格缩进呢......
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值