奇怪的知识增加了

奇怪的知识增加了近日闲来无事,总有一种无形的力量萦绕在朕身边,让朕精神涣散,昏昏欲睡。可是,像朕这么有职业操守的社畜怎么能在上班期间睡瞌睡呢,我不禁陷入了沉思。。。。突然旁边的IOS同事问:‘嘿,兄弟,我发现一个网站的图片很有意思啊,能不能帮我保存下来提升我的开发灵感?’作为一个坚强的社畜怎么能说自己不行呢,当时朕就不假思索的答应:‘oh,It’ssimple.Waitformefora…

大家好,又见面了,我是你们的朋友全栈君。

近日闲来无事,总有一种无形的力量萦绕在朕身边,让朕精神涣散,昏昏欲睡。
在这里插入图片描述
可是,像朕这么有职业操守的社畜怎么能在上班期间睡瞌睡呢,我不禁陷入了沉思。。。。
在这里插入图片描述
突然旁边的IOS同事问:‘嘿,兄弟,我发现一个网站的图片很有意思啊,能不能帮我保存下来提升我的开发灵感?’
作为一个坚强的社畜怎么能说自己不行呢,当时朕就不假思索的答应:‘oh, It’s simple. Wait for me a few minute.’
在这里插入图片描述
点开同事给的图片网站,
网站大概长这样:
在这里插入图片描述
在朕翻看了几十页之后,朕突然觉得有点上头。心中一想’不对啊,朕不是来学习的吗?可是看美女图片这个事情怎么才可以和学习关联起来呢‘
在这里插入图片描述
冥思苦想一番之后,突然脑中灵光一闪,’要不用python写个爬虫吧,将此网站的图片一网打尽‘。
在这里插入图片描述
说干就干,身体力行,要问爬虫哪家强,‘人生苦短,我用python’。
首先找到我的电脑里面半年前下载的python安装包,无情的点击了安装,环境装好之后,略一分析网页结构。先撸一个简易版爬虫

#抓取爱小姐姐网图片保存到本地
import requests
from lxml import etree as et
import os

#请求头
headers = { 
   
    #用户代理 
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

#待抓取网页基地址
base_url = ''
#保存图片基本路径
base_dir = 'D:/python/code/aixjj/'
#保存图片
def savePic(pic_url):
    #如果目录不存在,则新建
    if not os.path.exists(base_dir):
        os.makedirs(base_dir)
    
    arr = pic_url.split('/')
    file_name = base_dir+arr[-2]+arr[-1]
    print(file_name)
    #获取图片内容
    response = requests.get(pic_url, headers = headers)
    #写入图片
    with open(file_name,'wb') as fp:
        for data in response.iter_content(128):
            fp.write(data)

#观察此网站总共只有62页,所以循环62次
for k in range(1,63):
    #请求页面地址
    url = base_url+str(k)
    response = requests.get(url = url, headers = headers)
    #请求状态码
    code = response.status_code
    if code == 200:
        html = et.HTML(response.text)
        #获取页面所有图片地址
        r = html.xpath('//li/a/img/@src')
        #获取下一页url
        #t = html.xpath('//div[@class="page"]/a[@class="ch"]/@href')[-1]
        for pic_url in r:
            a = 'http:'+pic_url
            savePic(a)
    print('第%d页图片下载完成' % (k))

print('The End!')

尝试运行爬虫,嘿,没想到行了:

在这里插入图片描述
在这里插入图片描述
过了一会儿,旁边的哥们儿又来:‘嘿 bro 你这个可以是可以,就是速度太慢了啊,我的灵感会被长时间的等待磨灭,你给改进改进?’
在这里插入图片描述
怎么提升爬虫的效率呢?略一思索,公司的电脑可是伟大的四核CPU啊,要不撸个多进程版本试试。然后就产生了下面这个多进程版本

#多进程版——抓取爱小姐姐网图片保存到本地

import requests
from lxml import etree as et
import os
import time
from multiprocessing import Pool

#请求头
headers = { 
   
    #用户代理 
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

#待抓取网页基地址
base_url = ''
#保存图片基本路径
base_dir = 'D:/python/code/aixjj1/'

#保存图片
def savePic(pic_url):
    #如果目录不存在,则新建
    if not os.path.exists(base_dir):
        os.makedirs(base_dir)
    
    arr = pic_url.split('/')
    file_name = base_dir+arr[-2]+arr[-1]
    print(file_name)
    #获取图片内容
    response = requests.get(pic_url, headers = headers)
    #写入图片
    with open(file_name,'wb') as fp:
        for data in response.iter_content(128):
            fp.write(data)

def geturl(url):
    #请求页面地址
    #url = base_url+str(k)
    response = requests.get(url = url, headers = headers)
    #请求状态码
    code = response.status_code
    if code == 200:
        html = et.HTML(response.text)
        #获取页面所有图片地址
        r = html.xpath('//li/a/img/@src')
        #获取下一页url
        #t = html.xpath('//div[@class="page"]/a[@class="ch"]/@href')[-1]
        for pic_url in r:
            a = 'http:'+pic_url
            savePic(a)

if __name__ == '__main__':
    #获取要爬取的链接列表
    url_list = [base_url+format(i) for i in range(1,100)]
    a1 = time.time()
    #利用进程池方式创建进程,默认创建进程数量=电脑核数
    #自己定义进程数量方式 pool = Pool(4)
    pool = Pool()
    pool.map(geturl,url_list)
    pool.close()
    pool.join()
    b1 = time.time()
    print('运行时间:',b1-a1)

抱着试一试的心态,运行了多进程版本爬虫,嘿没想到又行了,在朕伟大的四核CPU的加持下,爬虫速度提升了3~4倍。
又过了一会儿,那哥们儿又偏过头来:‘你这个快是快了不少,但是还不是最理想的状态,能不能一眨眼就能爬取百八十个图片,毕竟我的灵感来的快去的也快’

我:‘…’
悄悄打开Google,搜索如何提升爬虫效率,给出结论:

多进程:密集CPU任务,需要充分使用多核CPU资源(服务器,大量的并行计算)的时候,用多进程。
多线程:密集I/O任务(网络I/O,磁盘I/O,数据库I/O)使用多线程合适。

呵,我这可不就是I/O密集任务吗,赶紧写一个多线程版爬虫先。于是,又诞生了第三款:

import threading # 导入threading模块
from queue import Queue #导入queue模块
import time  #导入time模块
import requests
import os
from lxml import etree as et

#请求头
headers = { 
   
    #用户代理 
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
#待抓取网页基地址
base_url = ''
#保存图片基本路径
base_dir = 'D:/python/code/aixjj/'

#保存图片
def savePic(pic_url):
    #如果目录不存在,则新建
    if not os.path.exists(base_dir):
        os.makedirs(base_dir)
    
    arr = pic_url.split('/')
    file_name = base_dir+arr[-2]+arr[-1]
    print(file_name)
    #获取图片内容
    response = requests.get(pic_url, headers = headers)
    #写入图片
    with open(file_name,'wb') as fp:
        for data in response.iter_content(128):
            fp.write(data)

# 爬取文章详情页
def get_detail_html(detail_url_list, id):
    while True:
        url = detail_url_list.get() #Queue队列的get方法用于从队列中提取元素
        response = requests.get(url = url, headers = headers)
        #请求状态码
        code = response.status_code
        if code == 200:
            html = et.HTML(response.text)
            #获取页面所有图片地址
            r = html.xpath('//li/a/img/@src')
            #获取下一页url
            #t = html.xpath('//div[@class="page"]/a[@class="ch"]/@href')[-1]
            for pic_url in r:
                a = 'http:'+pic_url
                savePic(a)

# 爬取文章列表页
def get_detail_url(queue):
    for i in range(1,100):
        #time.sleep(1) # 延时1s,模拟比爬取文章详情要快
        #Queue队列的put方法用于向Queue队列中放置元素,由于Queue是先进先出队列,所以先被Put的URL也就会被先get出来。
        page_url = base_url+format(i)
        queue.put(page_url)
        print("put page url {id} end".format(id = page_url))#打印出得到了哪些文章的url

#主函数
if __name__ == "__main__":
    detail_url_queue = Queue(maxsize=1000) #用Queue构造一个大小为1000的线程安全的先进先出队列
    #A线程负责抓取列表url
    thread = threading.Thread(target=get_detail_url, args=(detail_url_queue,)) 
    html_thread= []
    #另外创建三个线程负责抓取图片
    for i in range(20):
        thread2 = threading.Thread(target=get_detail_html, args=(detail_url_queue,i))
        html_thread.append(thread2)#B C D 线程抓取文章详情
    start_time = time.time()
    # 启动四个线程
    thread.start()
    for i in range(20):
        html_thread[i].start()
    # 等待所有线程结束,thread.join()函数代表子线程完成之前,其父进程一直处于阻塞状态。
    thread.join()
    for i in range(20):
        html_thread[i].join()
    print("last time: {} s".format(time.time()-start_time))#等ABCD四个线程都结束后,在主进程中计算总爬取时间。

粗略测试一下,得出结论: ‘Oh my god,这也太快了吧’。
将多线程版本爬虫扔到同事QQ头像的脸上,并附文:‘拿去,速滚’

The End!

在现实中,我忍气吞声,不敢侮辱别人,在网络上,我重拳出击,辱骂网友,意气风发!
天不生我键盘侠,喷道万古如长夜。
键来!仙之巅,傲世间,有我键盘就有天,天下键仙三百万,遇我也需尽低眉,我为键帝自当镇压世间一切敌。
谁在称无敌,哪个言不败,键化自在法。
键来!大盘之键天上来,奔流扣字不复回,待到逆乱阴阳时,以我魔键扣青天,大天造化键…

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/160316.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 算法导论答案网站_算法导论附录C答案

    算法导论答案网站_算法导论附录C答案//16.2-4#includeusingnamespacestd;#defineN6intx[N+1]={0,10,40,60,90,120,140},f[N+1]={0};//f用于标记某一站是否加油,x[i]表示第i个加油站距离起始点的距离voidGreedy_Select(intx[],intf[])//选择在哪一个加油站停车{ intn=30;//邮箱

    2025年5月27日
    2
  • java bigdecimal除法(java加减乘除运算)

    BigDecimal bignum1 = new BigDecimal("10");  BigDecimal bignum2 = new BigDecimal("5");  BigDecimal bignum3 = null;    //加法  bignum3 =  bignum1.add(bignum2);       System.out.println("和 是:" + bignum3); …

    2022年4月14日
    289
  • 安捷伦频谱仪的使用方法图解_安捷伦E4402B频谱仪使用说明

    安捷伦频谱仪的使用方法图解_安捷伦E4402B频谱仪使用说明标签:安捷伦仪器使用说明安捷伦仪器使用说明本资料为安捷伦频谱仪器使用说明,资料用于学习交流不能以任何形式商用。文档内容节选AgilentE4402BESAESeriesSpectrumAnalyzer使用方法简介宁波之猫2009617…

    2022年8月11日
    6
  • java语言打印出菱形_java怎么打印菱形

    java语言打印出菱形_java怎么打印菱形Java典型例题(打印菱形)题目:利用*号打印出一个菱形图样分析:下面逐步分析菱形打印的推演过程推演过程利用单独的方法演示,使用时直接在主方法中调用对应的方法即可。第一步,打印一行*号/**打印出如下图形: ********/publicstaticvoidprint01(){//每次打印一个星星for(inti=1;i<=7;i++){…

    2022年9月29日
    4
  • LoadRunner教程(7)-LoadRunner 创建测试场景

    LoadRunner教程(7)-LoadRunner 创建测试场景首先打开controller创建一个场景,有手工场景和目标场景设置两个选项,先选择手工场景手工场景设置GlobalSchedule:Scenario初始化:所有用户同时初始化,每隔多少秒初始化多少用户,每个用户运行之前初始化启动用户:多少用户启动,同时启动,每隔多长时间启动多少用户运行时间:持续运行直到结束,持续运行时间用户退出:用户同时退出,每隔多长时间…

    2022年5月10日
    46
  • 赚一个亿真的不难,不信你看下面代码

    赚一个亿真的不难,不信你看下面代码privatevoidComputeActionPerformed(java.awt.event.ActionEventevt){//TODOaddyourhandlingcodehere:if(Salary.getText().isEmpty()||Aim.getText().isEmpty()||Saving.getText().isEmpty()){..

    2022年6月12日
    29

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号