多线程爬取斗图啦图片
爬取斗图啦的表情包对于入门的同学来说很简单,但是对于小编这种不会多线程的人来说,这是个很好的练习多线程的机会。
由于小编是在读生,所以花了两天的课余时间去做这个程序,最大的困惑就是:
为什么第一天爬取斗图啦每两页就积极拒绝我?这么容易就识别出爬虫了,然后小编就用了代理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