上一篇我们写了python实现图片爬取的实例,有兴趣可以看看
地址:https://blog.youkuaiyun.com/stonezry/article/details/106072145
我们还是实现和上面相同的功能,只是这里我们运用了线程和队列进行实现。
python的线程创建方法,这里有两种方法。
1. 将要执行的方法作为参数传给Thread的构造方法 target传递方法名字,args传递方法参数。 如下
#!/usr/bin/python3
import threading import time
# 为线程定义一个函数
def printtime( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print (“%s: %s” % ( threadName, time.ctime(time.time()) ))
if __name__ == '__main__'::
# 创建两个线程
t = threading.Thread(target=printtime, args=(“Thread-1”, 2,))
t.start()
t = threading.Thread(target=printtime, args=(“Thread-2”, 1,))
t.start()
2. 从Thread继承,并重写run()
class MyThread(threading.Thread):
def init(self, arg):
threading.Thread.init(self)
# 注意:这里一定要显式的调用初始化函数。
self.arg=arg
def run(self): #定义每个线程要运行的函数
pass
arg = 'haha'
t = MyThread(arg)
t.start()
附:
- run(): 用以表示线程活动的方法。
- start(): 启动线程活动。
- join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
- isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- **setName(): **设置线程名。
队列的使用
队列的创建
- q = Queue.Queue(),默认为先进先出队列。
- q = Queue.LifoQueue(),后进先出队列
- q = Queue.PriorityQueue(),优先级队列
以上三种队列参数均可以传递一个最大的队列数值maxsize。
- Queue.qsize() 返回队列的大小
- Queue.empty() 如果队列为空,返回True,反之False
- Queue.full() 如果队列满了,返回True,反之False,Queue.full 与 maxsize 大小对应
- Queue.get([block[, timeout]])获取队列,timeout等待时间
- Queue.getnowait() 相当Queue.get(False)
- Queue.put(item) 写入队列,timeout等待时间
- Queue.putnowait(item) 相当Queue.put(item, False)
- Queue.taskdone() 在完成一项工作之后,Queue.taskdone()函数向任务已经完成的队列发送一个信号 Queue.join() 实际上意味着等到队列为空,再执行别的操作
简单介绍完线程和队列,我们开始实现我们的图片加载。 这里我们创建两个线程,线程t1用来过滤出需要加载的图片地址,线程t2用来加载图片并保存到本地文件。
t2的结束与否,通过判断t1是否还在运行以及队列是否为空来进行判断处理。
完整代码:
import threading
import queue
import re
import urllib.request
import urllib.parse
import time
import urllib.error
import ssl
# 使用代理服务器
def use_proxy(proxy_addr, url):
try:
ssl._create_default_https_context = ssl._create_stdlib_context
#设置代理
# proxy = urllib.request.ProxyHandler({'https': proxy_addr})
# opener = urllib.request.build_opener(proxy)
opener = urllib.request.build_opener()
# 模拟成浏览器
headers = {"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"}
request = urllib.request.Request(url, headers=headers)
data = opener.open(request).read()
return data
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
time.sleep(1)
except Exception as e:
print("exception:" + str(e))
time.sleep(1)
# 线程1,专门获取对应网址并处理成真实网址
class UrlThread(threading.Thread):
def __init__(self, pagestart, pageend, proxy, urlqueue):
threading.Thread.__init__(self)
self.pagestart = pagestart
self.pageend = pageend
self.proxy = proxy
self.urlqueue = urlqueue
def run(self):
for page in range(self.pagestart, self.pageend):
index = 2 * page - 1
s = index * 30
data_query = {
'keyword': '手机',
'wq': '手机',
'page': page,
's': s,
'click': 0
}
url = 'https://search.jd.com/Search?' + urllib.parse.urlencode(data_query)
print(url)
# 使用代理服务器爬取,解决ip被封杀问题
data1 = str(use_proxy(self.proxy, url))
# url正则
pat = '<img width="220" height="220" data-img="1" src="//(.+?.jpg)" data-lazy-img="done" />'
listurl = re.compile(pat).findall(data1)
# 便于调试
print("获取到第" + str(page) + "页,该页有" + str(len(listurl)) + "个")
for i in range(0, len(listurl)):
try:
url = listurl[i]
# 处理成真实的图片地址url
url = "http://" + url
print("第" + str(page) + "页,第" + str(i) + "个图片地址入队列")
self.urlqueue.put(url)
self.urlqueue.task_done()
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
except Exception as e:
print("exception:" + str(e))
time.sleep(1)
# 线程2,加载图片
class ImgThread(threading.Thread):
def __init__(self, urlqueue, proxy, thd):
threading.Thread.__init__(self)
self.urlqueue = urlqueue
self.proxy = proxy
self.thd = thd
def run(self):
i = 1
while (self.thd.is_alive() or not self.urlqueue.empty()):
try:
url = self.urlqueue.get()
print(url)
if (url):
imagename = "/Users/zhouruiyong/Desktop/python/img/" + str(i) + ".jpg"
urllib.request.urlretrieve(url, filename=imagename)
print("第" + str(i) + "个图片加载")
i += 1
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
except Exception as e:
print("exception:" + str(e))
if __name__ == '__main__':
urlqueue = queue.Queue()
proxy = "122.224.65.201:3128"
pagestart = 1
pageend = 3
print("程序执行开始")
# 创建线程1并启动,主要是将爬取的图片地址加入队列
print("UrlThread 线程。。。")
t1 = UrlThread(pagestart, pageend, proxy, urlqueue)
t1.start()
# 创建线程2,从队列中获取图片地址并加载到本地文件夹
print("contentThread 线程。。。")
t2 = ImgThread(urlqueue, proxy, t1)
t2.start()
t1.join()
t2.join()
print("程序执行完毕!")
这里我们加入了代理访问,如果你选择的代理地址失效,就会反问失败,可以多试几个代理地址。不过因为用代理速度太慢了,所以这里把设置代理的代码注释了。
欢迎关注本人公众号和小程序,谢谢