python-(6-6-1)爬虫---线程(池)、进程(池)与实战案例

一 进程(池)和线程(池)

进程是系统资源分配的最小单位,每个进程至少要有一个线程。
启动一个进程,默认会有一个主线程。

进程是任务执行的最小单位。

进程和线程的关系,类似于企业和人的关系。
一个企业如果存在,则至少有一个人(老板);
企业(进程)的运行,对内离不开人(线程)的付出,对外作为单独个体,需要市场和政府政策(系统资源)的帮助。

线程池:一次性开辟一些线程,用户直接给线程池提交任务,由线程池调度线程任务。

二 创建多线程

(一)方法一

from threading import Thread

# 定义第一个函数
def func1(name1):
    for i in range(1,100):
        print(name1, i)

# 定义第二个函数
def func2(name2):
    for i in range(101,200):
        print(name2, i)

# 定义主函数
if __name__ == '__main__':
    # 为func1创建为线程t1,参数args必须是元组
    t1 = Thread(target=func1, args=("线程1",))
    # 设置t1可以开始工作,具体执行时间由CPU决定
    t1.start()

    # 为func2创建为线程t2
    t2 = Thread(target=func2,args=("线程2",))
    # 设置t2可以开始工作,具体执行时间由CPU决定
    t2.start()

    # 主函数也作为其中一个线程进行工作
    for i in range(201,300):
        print("main", i)

(二)方法二

from threading import Thread

# MyThread继承了Thread
class MyThread(Thread):
    # 当线程被执行的时候,被执行的就是run()
    def run(self):
        for i in range(101,200):
            print("子线程:", i)

if __name__ == "__main__":
    # 创建MyThread子线程
    t = MyThread()
    # 开启子线程
    t.start()

    # 执行主线程
    for i in range(100):
        print("主线程:", i)

三 创建多进程

from multiprocessing import Process

# 定义子进程
def func():
    for i in range(10001,20000):
        print("子进程:", i)


if __name__ == '__main__':
    # 创建子进程
    p = Process(target=func)
    # 开启子进程
    p.start()

    # 创建并执行主进程
    for i in range(10000):
        print("主进程:", i)

创建多进程的第二种方法和多线程一样,只要将相关参数替换即可。

四 创建线程池和进程池

# 导入线程池和进程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

def fu(name):
    for i in range(1000):
        print(name, i)

# 线程池
if __name__ == '__main__':
    # 创建线程池,分配50个线程
    with ThreadPoolExecutor(50) as t:
        for i in range(100):
            t.submit(fu, name=f"线程{i}")

    # (守护)等待线程池全部执行完,才会执行
    print("thread over!!!")

# 进程池
if __name__ == '__main__':
    # 创建进程池,分配50个进程
    with ProcessPoolExecutor(50) as p:
        for i in range(100):
            p.submit(fu, name=f"进程{i}")

    # (守护)等待进程池全部执行完,才会执行
    print("process over!!!")

五 多线程获取数据案例

此处选用了某农产品价格网站。
笔者在写这篇文章时,由于服务器内部错误,无法得到所有数据,只得到了第一页的数据。
因此如果最终没有得到想要的结果,不妨打开网站看一看,可能是对方的错误。

此处涉及的xpath知识点,如果看不懂,可以参考笔者的文章。
python-(6-5-1)爬虫—xpath解析实战

import requests
from lxml import etree
import csv
from concurrent.futures import ThreadPoolExecutor

# 创建data.csv文件,准备将数据写入该文件
f = open("data.csv", mode="w", encoding='utf-8')
csvwriter = csv.writer(f)

def download_one_page(url):
    resp = requests.get(url)
    html = etree.HTML(resp.text)
    table = html.xpath("/html/body/div[4]/div[4]/div[1]/table")[0]

    # 去掉表头
    #trs = table.xpath("./tr")[1:]
    trs = table.xpath("./tr[position()>1]")
    # 拿到每个tr
    for tr in trs:
        txt = tr.xpath("./td/text()")
        # 对数据简单处理:去掉/ \\
        txt = (item.replace("\\", "").replace("|", "") for item in txt)
        # 把数据存放在文件中
        csvwriter.writerow(txt)
    print(url, "提取完成!!!")
    # 访问请求结束后,关闭网页
    resp.close()

if __name__ == '__main__':
    # 创建线程池
    with ThreadPoolExecutor(50) as t:
        for i in range(200):
            # 把下载任务提交给线程池
            t.submit(download_one_page, f"https://www.construdip.com/marketanalysis/0/list/{i}.shtml")
    # 写完数据后,关闭网页
    f.close()
    print("全部下载完毕!!!!")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值