php多线程抓取多个网页(小白:多线程便携的数据使用流程及常用方法 )
优采云 发布时间: 2021-09-22 00:20php多线程抓取多个网页(小白:多线程便携的数据使用流程及常用方法
)
修剪小白色,最近被一位高手的B站学习,这里,请,请“
运行结果:
1:多线程:CPU密集型程序适用于多线程,您可以充分利用计算机的多核,通常使用单线程采集数据较慢,多线程是多个行执行的任务返回这个过程
穿线模块==============================“”“”“线程模块
使用过程:
t =线程(目标=事件函数名称)
t.start()
t.join()#块等待线程以避免堵塞线程生成
多线程应用方案:
io操作更多程序,包括网络IO,本地磁盘IO
Reptral部分请求响应:网络IO
爬网程序处理的重新启动:本地磁盘IO
因此,使用多线程*敏*感*词*爬行动物可以提高抓取数据的效率
2:队列:当多个进程执行任务时,它易于阻止,数据无法确定数据,因此队列解决了此问题,使用
将数据放入队列中。
在提取
fromqueue import queue
通用方法:
创建队列q = queue()
进入队列:q.put()
导出:q.get()
确定队列是否为空:q.empty()
关闭解决方案时为空值:
·q.get(block = true,timeout = 2) @ @ jdeast延迟时间2秒后2秒,
·.get(block = false)
·虽然不是q.empty():
q.get()
3:线程锁:当多个线程操作相同的共享资源时,当在下面的时间启动其中一个进程时,不会阻止锁定。
履带:
这个爬行是腾讯招募,攀登工作岗位的具体信息,总共有两个页面
想法
获得两页,您可以发现第一个需要更改是我们需要找到的位置,第二个是PageIndex是页数,第二个横向跳转是唯一的变量PostId,只需要提取物POSTID作为第一页中第二页的POSTID。这将获得两个页面信息。
在第一页中,获取POSTID,准备跳转链接,并在第二页中获取作业信息。其中,需要两个队列和2个线程锁,页面应该是队列和线程锁定
代码:
定义连接,队列,线程锁定
def __init__(self):
self.one_q=Queue()#队列1
self.two_q=Queue()#队列2
self.one_lock=Lock()#锁1
self.two_lock=Lock()#锁2
self.number=0
self.one_url='https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1630301002746&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword={}&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
self.two_url='https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1630388009179&postId={}&language=zh-cn'
self.headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
}
首次访问需要输入队列,Word是可以手动输入的作业名称,URllib.parse.quote(kw)将输入的汉字转到计算机可识别的编码,总= self.get_total(Word)是一个自定义的功能,当未确认页数以及完全连接时,自动获取帖子中的页数。 self.one_q.put(one_url)将在队列中连接
def url_in(self):
kw=input('请输入想查找的职位:')
word=urllib.parse.quote(kw)
total=self.get_total(word)
for pageindex in range(1,total+1):
one_url=self.one_url.format(word,pageindex)
self.one_q.put(one_url)
此代码写入上面的总功能,页数
def get_total(self,word):
one_url=self.one_url.format(word,1)
html=requests.get(url=one_url,headers=headers).json()
count=html['Data']['Count']
total=count//10 if count==0 else count//10+1
print(total)
return total
接下来解析连接以获取POSTID,完成链接到跳转页面,线程锁定内部,但锁将打开下一个进程,只要队列不为空,请携带链接,然后分析,如果它是空的,退出
def one_parse(self):
while True:
self.one_lock.acquire() #避免多个线程判断一个队列,锁了
if not self.one_q.empty():
one_url=self.one_q.get()
self.one_lock.release()#开锁
html=requests.get(url=one_url,headers=self.headers).json()
rep=html['Data']['Posts']
for i in rep:
post_id=i['PostId']
URL=self.two_url.format(post_id)。#完成需要的二级链接
#给二级队列
self.two_q.put(URL)
#print(URL)
else:
self.one_lock.release()
break
有必要强调,每当放置队列时,最初需要写入使用的功能,但在队列之后,def括号内的使用对象都在队列中,无需写入,默认自我
下一个是得到第二页=====“主要所需作业的主要信息
def two_parse(self):
while True:
try:
self.two_lock.acquire()
URL=self.two_q.get(timeout=3) #一级页面和二级页面容易冲突,时间延迟等一级页面首先完成
self.two_lock.release()
html=requests.get(url=URL,headers=self.headers).json()
item={}
item['name']=html['Data']['RecruitPostName']
item['typ']=html['Data']['CategoryName']
item['add']=html['Data']['LocationName']
item['req']=html['Data']['Requirement']
item['duty']=html['Data']['Responsibility']
self.two_lock.acquire()
self.number+=1
self.two_lock.release()
print(item)
except Exception as e:
self.two_lock.release()
break
最后,使用直接多线程,将两个队列放入两个线程可以运行
def run(self):
self.url_in()
#创建多线程
t1_list=[]
t2_list=[]
for i in range(2):
t1=Thread(target=self.one_parse)
t1_list.append(t1)
t1.start()
for i in range(2):
t2=Thread(target=self.two_parse)
t2_list.append(t2)
t2.start()
for t1 in t1_list:
t1.join()
for t2 in t2_list:
t2.join()
完成代码
'''多级页面的多线程---腾讯招聘'''
import requests
from threading import Thread,Lock
from queue import Queue
import urllib.parse
import json,time
class Tenxun():
def __init__(self):
self.one_q=Queue()
self.two_q=Queue()
self.one_lock=Lock()
self.two_lock=Lock()
self.number=0
self.one_url='https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1630301002746&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword={}&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
self.two_url='https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1630388009179&postId={}&language=zh-cn'
self.headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
}
def url_in(self):
kw=input('请输入想查找的职位:')
word=urllib.parse.quote(kw)
total=self.get_total(word)
for pageindex in range(1,total+1):
one_url=self.one_url.format(word,pageindex)
self.one_q.put(one_url)
def get_total(self,word):
one_url=self.one_url.format(word,1)
html=requests.get(url=one_url,headers=headers).json()
count=html['Data']['Count']
total=count//10 if count==0 else count//10+1
print(total)
return total
def one_parse(self):
while True:
self.one_lock.acquire() #避免多个线程判断一个队列,锁了
if not self.one_q.empty():
one_url=self.one_q.get()
self.one_lock.release()
html=requests.get(url=one_url,headers=self.headers).json()
rep=html['Data']['Posts']
for i in rep:
post_id=i['PostId']
URL=self.two_url.format(post_id)
#给二级队列
self.two_q.put(URL)
#print(URL)
else:
self.one_lock.release()
break
def two_parse(self):
while True:
try:
self.two_lock.acquire()
URL=self.two_q.get(timeout=3) #一级页面和二级页面容易冲突,时间延迟等一级页面首先完成
self.two_lock.release()
html=requests.get(url=URL,headers=self.headers).json()
item={}
item['name']=html['Data']['RecruitPostName']
item['typ']=html['Data']['CategoryName']
item['add']=html['Data']['LocationName']
item['req']=html['Data']['Requirement']
item['duty']=html['Data']['Responsibility']
self.two_lock.acquire()
self.number+=1
self.two_lock.release()
print(item)
except Exception as e:
self.two_lock.release()
break
def run(self):
self.url_in()
#创建多线程
t1_list=[]
t2_list=[]
for i in range(2):
t1=Thread(target=self.one_parse)
t1_list.append(t1)
t1.start()
for i in range(2):
t2=Thread(target=self.two_parse)
t2_list.append(t2)
t2.start()
for t1 in t1_list:
t1.join()
for t2 in t2_list:
t2.join()
if __name__=="__main__":
start_time=time.time()
spider=Tenxun()
spider.run()
end_time=time.time()
print('time:%.2f'%(end_time-start_time))