这几天帮同学爬取拉勾网的招聘信息,真好学习一下多线程爬虫,之前做过几次爬虫都是单线程的。看到网上说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()