一只爬虫太慢,那就来一群吧
标签: 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空间的排版真是个坑,说好的严格缩进呢......