Python

[CP_12] Python多线程爬虫应用实践(社招职位名称获取

2019-04-07  本文已影响0人  Fighting_001

目录结构

一、多线程爬虫的使用
    1. 多线程实现
    2. 自定义创建线程类
    3. Python队列
二、多线程爬虫应用案例
    案例:爬取指定页码的招聘职位名称

一、多线程爬虫的使用

1. 多线程实现

<关联> [Pt_04] Python进程|多进程|线程|多线程|线程锁

multiThread-001.py

import threading
import time

# 定义执行线程的方法
def run(name):
    print(name,"线程执行")
    time.sleep(3)

# 创建2个线程;线程执行run方法
t1=threading.Thread(target=run,args=("t001",))
t2=threading.Thread(target=run,args=("t002",))

# 启动线程
t1.start()
t2.start()

# 等待子线程(t1,t2)执行完毕,再执行主线程(print输出的内容)
t1.join()
t2.join()

print("执行完毕!")

2. 自定义创建线程类

使用threading模块创建线程,创建一个新的子类继承父类threading.Thread,实例化后即可调用start()方法,该方法调用了线程的run()方法来启动新线程

threadClass.py

import threading
import time

# 创建一个线程锁
lock=threading.Lock()

# 创建线程类(继承threading.Thread)
class myThread(threading.Thread):

    def __init__(self,name):
        threading.Thread.__init__(self)
        self.name=name

    def run(self):
        lock.acquire()  # 设置锁
        print(self.name,"线程开始执行")
        print("线程执行中---1")
        time.sleep(1)
        print("线程执行中---2")
        time.sleep(1)
        print("线程执行中---3")
        time.sleep(1)
        print("线程执行中---4")
        time.sleep(1)
        print("线程执行中---5")
        time.sleep(1)       
        print(self.name,"线程结束")
        lock.release()  # 释放锁

# 创建线程
t1=myThread("t001")
t2=myThread("t002")
t3=myThread("t003")

# 开启线程
t1.start()
t2.start()
t3.start()

# 等待子线程执行完毕,再执行主线程
t1.join()
t2.join()
t3.join()

print("执行完毕!")

执行结果:

3. Python队列

队列(Queue):保障Python标准库中的线程安全的实现,提供了一个适用于多线程的"先进先出"(First-In-First-Out,FIFO)的数据结构。对于排队的一序列任务,通过队列进行维护管理,保障先来先处理,处理完成一个再处理另一个,从而有序的执行线程而不错乱

queueTask.py

import queue

# 创建队列(maxsize限定队列存放的数据个数上限)
q=queue.Queue(maxsize=10)

# 向队列中放入值or对象
for i in range(1,11):
    q.put(i)

# 队列不为空时,循环取出所有值
while not q.empty():
    print(q.get())

执行结果:

二、多线程爬虫应用案例

案例:爬取指定页码的招聘职位名称

分析:

2个线程,其中一个爬取列表的网页,将爬取的数据放入到队列中;另一个线程从刚才队列中拿到html页面进行解析数据,获取每一个职位的标题

页码链接:
https://hr.tencent.com/position.php?keywords=&lid=0&start=0#a
https://hr.tencent.com/position.php?keywords=&lid=0&start=10#a
https://hr.tencent.com/position.php?keywords=&lid=0&start=20#a
==> start=(页码-1)*10

列表页-职位标题:

代码实现:

multiThread-002.py

import threading
import queue
import requests
import time
from lxml import etree

# 采集网页的线程:爬取列表所在的网页,放入队列
class Thread1(threading.Thread):

    def __init__(self,threadName,pageQueue,dataQueue):
        threading.Thread.__init__(self)
        self.threadName=threadName  # 线程名
        self.pageQueue=pageQueue    # 页码队列
        self.dataQueue=dataQueue    # 数据队列
        self.header={"User-Agent":"Mozilla/5.0 (Windows NT 6.1; rv:65.0) Gecko/20100101 Firefox/65.0"}

    def run(self):
        print("启动线程"+self.threadName)
        while not flag1:
            try:
                page=self.pageQueue.get()
                url="https://hr.tencent.com/position.php?"+"start="+str((page-1)*10)+"#a"
                # 获取列表信息转换为文本
                resp=requests.get(url,headers=self.header).text
                time.sleep(1)   # 拿到数据和放入数据的过渡时间
                self.dataQueue.put(resp)    # 将数据放入dataQueue队列
            except Exception as e:
                pass
        print("结束线程"+self.threadName)

# 解析网页的线程:从队列中获取网页进行解析,存储到本地
class Thread2(threading.Thread):

    def __init__(self,threadName,dataQueue,filename):
        threading.Thread.__init__(self)
        self.threadName=threadName
        self.dataQueue=dataQueue
        self.filename=filename
        
    def run(self):
        print("启动线程"+self.threadName)
        while not flag2:
            try:
                dataQ=self.dataQueue.get()
                html=etree.HTML(dataQ)
                datalist=html.xpath('//td/a[@target="_blank"]')
                for i in datalist:
                    data=i.text
                    self.filename.write(data+"\n")
            except Exception as e:
                pass
        print("结束线程"+self.threadName)


flag1=False # 判断页码队列是否为空
flag2=False # 判断数据队列是否为空

def main():
    # 页码队列
    pageQueue=queue.Queue(10)
    for i in range(1,11):
        pageQueue.put(i)
    # 采集线程获取的数据放入队列
    dataQueue=queue.Queue()
    # 爬取数据的结果保存到本地的路径
    filename=open(r"D:\CI_Env\Python_Test\file\004.txt","a")

    # 启动线程
    t1=Thread1("t001",pageQueue,dataQueue)
    t1.start()
    t2=Thread2("t002",dataQueue,filename)
    t2.start()

    # pageQueue为空时,结束采集线程[run()方法中的while循环]
    while not pageQueue.empty():
        pass
    global flag1    # 定义为全局变量
    flag1=True

    # dataQueue为空时,结束解析线程
    while not dataQueue.empty():
        pass
    global flag2
    flag2=True

    # 等待子线程执行完毕,再执行主线程
    t1.join()
    t2.join()
    filename.close()

    print("执行完毕!")

if __name__ == '__main__':
    main()

执行结果:

上一篇 下一篇

猜你喜欢

热点阅读