zoukankan      html  css  js  c++  java
  • 多线程爬取斗图啦图片

    爬取斗图啦的表情包对于入门的同学来说很简单,但是对于小编这种不会多线程的人来说,这是个很好的练习多线程的机会。

    由于小编是在读生,所以花了两天的课余时间去做这个程序,最大的困惑就是:

    为什么第一天爬取斗图啦每两页就积极拒绝我?这么容易就识别出爬虫了,然后小编就用了代理IP

    然鹅,到了第二天,一用代理IP就拒绝,用自己的IP去爬取的话。。。爬了几百页都没问题

    当然了,代理IP用的是西刺上的,质量难说,但是我弄个了代理IP池,程序用的IP都是验证过的,所以很迷。。

    下面附上源码:

    import requests
    from bs4 import BeautifulSoup
    import threading
    import random
    import re
    import os
    
    
    # 全局变量统一大写!
    PAGE_URL = 'https://www.doutula.com/photo/list/?page='  # 某一页的url
    PAGE_LIST = [PAGE_URL + str(i) for i in range(101,1001)]
    IMAGE_URL=[]  #保存图片URL
    IMAGE_NAME=[]   #保存图片名称
    PAGE_LIST1=[]   #保存临时页数!
    #全局锁
    # gLock=threading.RLock()
    condition = threading.Condition()  #条件变量
    #创建3个消费者线程下载图片
    
    def download_img():
        # global PAGE_LIST  #这个代码中不用全局变量,因为PAGE_LIST没有同名的局部变量!
        while True:
            if condition.acquire():
                if len(IMAGE_URL)>0: #只要还有没下载的URL
                    #请求资源,锁住资源,锁的顺序很重要!
                    name1 = IMAGE_NAME.pop()
                    page1 = PAGE_LIST1.pop()
                    url1=IMAGE_URL.pop()
    
                    condition.notify()   #随机通知一个线程进入锁定池
                    condition.wait()  #进入等待池,调用这个方法将使线程进入Condition的等待池等待通知,并释放锁
    
                    page = re.compile('[0-9]+').findall(page1)[0]  #获得页数,当作次一级文件名
                    print(page)
                    for i,j in zip(url1,name1):
                        i=requests.get(i).content  #请求资源,获得图片内容content
                        dir='D:/doutu1/'+str(page)+''
                        if os.path.exists(dir) == False:  # 如果不存在文件夹名为该文件夹名,就创建
                            os.mkdir(dir)
                        try:    #可能存在非法字符
                            with open('D:/doutu1/'+str(page)+'/'+str(j)+'.jpg','wb')as file:
                                file.write(i)
                        except:
                            with open('D:/doutu1/'+str(page)+'/'+str(random.randint(1,100))+'.jpg','wb')as file:
                                file.write(i)
                else:
                    condition.notify()
                    condition.wait()#进入等待池,调用这个方法将使线程进入Condition的等待池等待通知,并释放锁
            condition.release()
            if len(PAGE_LIST)==0:
                os._exit(0)  #当没有需要爬取的页面时就退出程序
    
    #创建2个生产者线程来爬取表情的url
    def run():
        # global PAGE_LIST
        while True:
            if condition.acquire():   #把资源锁住,不让其他线程使用
                if len(PAGE_LIST)>0:  #只要还有可以爬取的页面就生产url
                    page_url=PAGE_LIST.pop()    #真实页数url,通过pop方法,因为多线程,哪一页不确定
                    rsp = requests.get(page_url, verify=False)  # 请求某一页数据
                    # img_html=etree.HTML(rsp.text)  #解析网页数据
                    img_html = BeautifulSoup(rsp.text, 'lxml')
                    # print(img_html)
                    img_list = img_html.find_all('img', attrs={'class': 'img-responsive lazy image_dta'})
                    # 由于网络不可能一直很流畅,src不会那么快加载,可能出现白茫茫表情,所以抓取data-original,这样就指向真实网址
                    img_url = [i['data-original'] for i in img_list]
                    img_namelist = img_html.find_all('p', attrs={'style': 'display: none'})
                    img_name = [i.text for i in img_namelist]
                    print(img_url)
                    # 添加进列表,锁住资源
                    PAGE_LIST1.append(page_url)
                    IMAGE_URL.append(img_url)
                    IMAGE_NAME.append(img_name)
                    condition.notify()
                    condition.wait()
                else:
                    condition.notify()  # 随机通知一个线程进入锁定池
                    condition.wait()  # 进入等待池
            condition.release()  #内部循环结束,锁释放
    
    
    def main():
        #创建2个生产者下载表情url
        for i in range(2):
            th1=threading.Thread(target=run)
            th1.start()
    
        # 创建4个消费者线程下载图片
        for j in range(4):
            th2=threading.Thread(target=download_img)
            th2.start()
    
    if __name__=='__main__':
        main()
    

    1.斗图啦这个程序是看视频学的,重点看多线程部分,链接是:https://study.163.com/course/courseLearn.htm?courseId=1005001016#/learn/video?lessonId=1051195841&courseId=1005001016

    2.视频上使用的是LOCK去锁住资源,程序中用的是condition变量,大家需要先用程序实现生产者消费者模型再理解源码好点,附上学习链接:

    https://www.cnblogs.com/tkqasn/p/5700281.html

    https://www.cnblogs.com/Unikfox/p/9704207.html

  • 相关阅读:
    第十八篇:在SOUI中实现PreTranslateMessage
    第十七篇:使用窗口的cache属性加速SOUI的渲染
    通过驱动向打印机发送一段(ESC)控制指令
    转一个希尔排序
    关于Memo或者Edit之类控件, 直接设置Text无法撤销的解决方案
    关于创建无窗体程序的一点心得
    在Vista或更高版本Windows系统中, 获取超大图标的办法
    随笔里的标签为啥不能用空格分隔??
    一个ICMP单元
    Delphi XE5 与其他版本共存
  • 原文地址:https://www.cnblogs.com/fodalaoyao/p/10589669.html
Copyright © 2011-2022 走看看