Python 多线程+队列:爬取某网站所有图片

实现思路

  • download_image(url, image_dir, image_no):将图片下载页的主图下载到本地。
  • get_image_url(url):拼接图片下载的 url(绝对路径)。由于网站中的图片 src 都是相对路径,因此需要在此函数中拼接图片的绝对路径。
  • get_page_url(url):获取图片浏览页中的图片下载页 url 和翻页 url。
  • task(queue):多线程的任务函数,调用上述 3 个函数。

代码

下载地址:https://github.com/juno3550/Crawler

  1 import requests
  2 import re
  3 import os
  4 import threading
  5 import queue  # Python的queue模块中提供了同步的、线程安全的队列类
  6 from bs4 import BeautifulSoup
  7 import traceback
  8 
  9 
 10 # 队列,用来存放图片下载页url和翻页url
 11 queue = queue.Queue()
 12 # 种子url
 13 result_urls = []
 14 # 图片命名的起始编号
 15 image_no = 0
 16 # 图片存储路径
 17 image_dir = "e:\\crawl_image"
 18 if not os.path.exists(image_dir):
 19     os.makedirs(image_dir)
 20 
 21 
 22 # 将图片下载到本地
 23 def download_image(url, image_dir, image_no):
 24     try:
 25         # 访问图片并设置超时时间
 26         r = requests.get(url, timeout=60)
 27         # 获取图片的后缀名
 28         image_ext = url.split(".")[-1]
 29         # 设置下载路径与图片名称
 30         image_name = str(image_no) + "." + image_ext
 31         image_path = os.path.join(image_dir, image_name)
 32         # 保存图片到本地
 33         with open(image_path, "wb") as f:
 34             f.write(r.content)
 35         print("图片【%s】下载成功,保存路径【%s】" % (url, image_path))
 36     except:
 37         print("图片下载失败【%s】" % url)
 38         traceback.print_exc()
 39         
 40         
 41 # 获取图片下载url(绝对路径)
 42 def get_image_url(url):
 43     # 由于网站中的图片url都是相对路径,因此需要在此函数中拼接图片的绝对路径
 44     # 获取网站首页链接
 45     try:
 46         home_page = re.match(r"http[s]?://\w+.\w+\.com", url).group()
 47         r = requests.get(url, timeout=60)
 48         r.encoding = "gbk"
 49         # 通过a标签获取其中的src下载路径
 50         # 通过BeautifulSoup解析网页内容
 51         soup = BeautifulSoup(r.text, "html.parser")
 52         image_a = soup.find_all("a", attrs={"id": "img"})  # 找出id属性值为img的a标签,即主图
 53         if image_a:
 54             # 获得图片的相对路径
 55             image_relative_url = re.search(r'src="(.+?)"', str(image_a[0])).group(1)
 56             # 拼接绝对路径
 57             image_abs_url = home_page + image_relative_url
 58             return image_abs_url
 59     except:
 60         print("获取图片下载url失败【%s】" % url)
 61         traceback.print_exc()
 62     
 63     
 64 # 获取图片浏览页中的图片下载页url和翻页url
 65 def get_page_url(url):
 66     try:
 67         home_page = re.match(r"http[s]?://\w+.\w+\.com", url).group()
 68         r = requests.get(url, timeout=60)
 69         r.encoding = "gbk"
 70         soup = BeautifulSoup(r.text, "html.parser")
 71         # 存储所有图片的a标签跳转url及翻页url
 72         image_page_urls = []
 73         image_a_lists = soup.find_all("a")
 74         for image_a in image_a_lists:
 75             # 获取a标签中的相对url
 76             relative_url = image_a["href"]
 77             # 根据url特征,只需要图片跳转页url和翻页url
 78             if relative_url.startswith("/tupian") and relative_url.endswith(".html") or "/index_" in relative_url:
 79                 # 拼接绝对路径
 80                 image_or_index_abs_url = home_page + relative_url
 81                 image_page_urls.append(image_or_index_abs_url)
 82         return image_page_urls
 83     except:
 84         print("获取图片下载页url和翻页url失败【%s】" % url)
 85         traceback.print_exc()
 86 
 87 
 88 # 任务函数
 89 def task(queue):
 90     global result_urls
 91     global image_dir
 92     global image_no
 93     while not queue.empty():
 94         url = queue.get()
 95         try:
 96             # 如果该页为主图页,则下载图片
 97             image_download_url = get_image_url(url)
 98             if image_download_url and image_download_url not in result_urls:
 99                 image_no += 1
100                 # 下载图片到本地
101                 download_image(image_download_url, image_dir, image_no)
102                 result_urls.append(image_download_url)
103         except:
104             traceback.print_exc()
105         try:
106             # 获取图片下载页url和翻页url,加入队列中
107             image_page_urls = get_page_url(url)
108             while image_page_urls:
109                 image_page_url = image_page_urls.pop()
110                 if image_page_url not in result_urls:
111                     queue.put(image_page_url)
112                     result_urls.append(image_page_url)
113         except:
114             traceback.print_exc()
115 
116 
117 if __name__ == "__main__":
118     # 将种子页面放入队列中
119     image_resource_url = "http://pic.netbian.com"
120     queue.put(image_resource_url)
121     # 开启100个线程,执行任务函数
122     t_list = []
123     for i in range(100):
124         t = threading.Thread(target=task, args=(queue,))
125         t_list.append(t)
126         t.start()
127     # 等待所有子线程结束后,主线程才结束
128     for t in t_list:
129         t.join()

执行结果

 

posted @ 2021-01-25 15:07  Juno3550  阅读(264)  评论(0编辑  收藏  举报