这几天帮同学爬取拉勾网的招聘信息,真好学习一下多线程爬虫,之前做过几次爬虫都是单线程的。看到网上说python由于GIL的存在,多线程的效果不好。但是当处理IO比较密集的任务时,网络请求时间较长时,多线程可以充分利用cpu资源。
1、先了解一下线程和进程的区别,这方面资料很多。
创建 一个url队列和out队列,url队列用来存放需要爬取的网站链接,out队列用来存放每个url爬取到的数据。
queue = Queue.Queue()
out_queue = Queue.Queue()
2、构造header,设置伪登录
request_headers = {
'host': "www.lagou.com",
'connection': "keep-alive",
'cache-control': "no-cache",
'user-agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Mobile Safari/537.36",
'accept': "application/json, text/javascript, */*; q=0.01",
'accept-language': "zh-CN,zh;q=0.9",
'cookie':" "
}
3、使用多线程从url队列中获得url进行解析,并把得到的结果放入到结果队列中out_queue
def run(self):
while True:
#grabs url from queue
url = self.queue.get()
#grabs urls of hosts and prints first 1024 bytes of page
requset = urllib2.Request(url,headers=request_headers)
try:
response=urllib2.urlopen(requset)
allcon=response.read()
soup = BeautifulSoup(allcon,"html.parser",from_encoding="gb18030")
except urllib2.URLError, e:
print e.reason
res = self.get_result(soup)
out_queue.put(res)
#signals to queue job is done
self.queue.task_done()
其中,queue.get()从队列中得到一个item,并将其进行删除,queue.task_done()监督该任务是否处理完毕
4、将结果从结果队列out_queue()中取出并写入到文件中。
def run(self):
while True:
res = self.out_queue.get()
# print res
#parse the chunk
f.write(res.encode('utf-8'))
#signals to queue job is done
self.out_queue.task_done()
5、填充队列,对队列执行join()操作
for i in range(1,4):
t = ThreadUrl(queue,out_queue)
t.setDaemon(True)
t.start()
type = 'Java'
for i in range(1,31):
url = 'https://www.lagou.com/zhaopin/'+str(type)+'/'+str(i)+'/?filterOption='+str(i)+'&city=北京'
queue.put(url)
for i in range(3):
t = WriteThread(out_queue)
t.setDaemon(True)
t.start()
queue.join()
out_queue.join()