多线程学习 遇到问题(一)基础代码

2020农历新年前后,一场新型肺炎病毒席卷全国,截止今天感染人数74000余人,响应号召在家呆了月余没有出门。决定重新学习多线程,更加深入的理解多线程,今天尝试一下就遇到一个问题,困扰两天,一经解决豁然开朗,算是一个小心得吧,那就是线程包裹的是方法,一个方法解决一个问题,把所有的相关代码都写到方法里边,这样爬虫才能起到作用,如果有代码留在外边,则不起作用。表达能力有限,看代码:
爬取不羞涩图片网站的图片

import time
import requests
from bs4 import BeautifulSoup
import threading


class Buxiuse(object):
    def __init__(self):
        self.i = 1
        url = 'https://www.buxiuse.com/?cid=3&page={}'
        self.page_urls = [url.format(i) for i in range(1, 11)]

    def parse_html(self, url):
        header = {
            'User - Agent': 'Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) '
                            'Chrome / 80.0.3987.106Safari / 537.36'
        }
        res = requests.get(url, headers=header)
        return res.content.decode('utf-8')

    # 解析页面 获得图片url列表
    def get_url_list(self, content):
        bs = BeautifulSoup(content, 'html.parser')
        img_list = bs.find_all('img', class_='height_min')
        return [i.get('src') for i in img_list]

    # 保存图片
    def save_pic(self, cont):
        with open('1/{}.jpg'.format(self.i), 'wb') as f:
            f.write(cont)
        print('{}.jpg 下载完成!'.format(self.i))
        self.i += 1

    def run(self):
        start = time.time()
        t_list = []
        # 遍历取出每一页的url
        for url in self.page_urls:
            # 获得页面里的 图片url列表
            url_list = self.get_url_list(self.parse_html(url))
            # 遍历 图片url列表
            for l in url_list:
                cont = requests.get(l).content
                t = threading.Thread(target=self.save_pic, args=(cont,))
                t_list.append(t)
                t.start()
            for i in t_list:
                i.join()
        end = time.time()
        print('总共时间:{}'.format(start - end))


if __name__ == '__main__':
    demo = Buxiuse()
    demo.run()

结构比较简单,爬取前10页的图片,也没有做信号量限制线程数。运行结果是38秒,比没有使用多线程还多出一秒。。。。
多次尝试,查资料没有所获,直到看到了这一行:
run()方法里的 cont = requests.get(l).content
作用是解析图片url获得图片的二进制代码,保存图片。
由于刚写这个代码的时候,没有用面向对象,改代码的时候,就把这行忽略了,仔细观察save_pic()方法,参数就是这个cont。
实际上,这句代码应该写在save_pic()方法里面,他出了给这个方法提供参数以外没有其他作用,所以我改了一下:

import time
import requests
from bs4 import BeautifulSoup
import threading


class Buxiuse(object):
    def __init__(self):
        self.i = 1
        url = 'https://www.buxiuse.com/?cid=3&page={}'
        self.page_urls = [url.format(i) for i in range(1, 11)]

    def parse_html(self, url):
        header = {
            'User - Agent': 'Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) '
                            'Chrome / 80.0.3987.106Safari / 537.36'
        }
        res = requests.get(url, headers=header)
        return res.content.decode('utf-8')

    # 解析页面 获得图片url列表
    def get_url_list(self, content):
        bs = BeautifulSoup(content, 'html.parser')
        img_list = bs.find_all('img', class_='height_min')
        return [i.get('src') for i in img_list]

    # 保存图片
    def save_pic(self, url):
        cont = requests.get(url).content
        with open('1/{}.jpg'.format(self.i), 'wb') as f:
            f.write(cont)
        print('{}.jpg 下载完成!'.format(self.i))
        self.i += 1

    def run(self):
        start = time.time()
        t_list = []
        # 遍历取出每一页的url
        for url in self.page_urls:
            # 获得页面里的 图片url列表
            url_list = self.get_url_list(self.parse_html(url))
            # 遍历 图片url列表
            for l in url_list:
                t = threading.Thread(target=self.save_pic, args=(l,))
                t_list.append(t)
                t.start()
            for i in t_list:
                i.join()
        end = time.time()
        print('总共时间:{}'.format(start - end))


if __name__ == '__main__':
    demo = Buxiuse()
    demo.run()

运行结果是 7秒多点。。。。多线程起作用了。
为啥呢
关键就是上边那一句,造成了cont只有一个,线程再多也没有用。

这段代码问题不少,如果内容很多会开过多线程,资源占用过多,或容易被反爬,而且运行以后发现,快是快了,可是爬下来的东西却比网页上少,这就是线程间资源抢夺的问题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值