Advertisement
shinemic

baidu_image_scrapper

Oct 27th, 2019
460
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.61 KB | None | 0 0
  1. """
  2. 百度图片批量下载(翻页版)
  3.  
  4. 默认的百度图片由下拉网页载入新的图片,一定程度给爬虫增大了难度
  5. 这里采用其可翻页版本爬取下载图片
  6.  
  7. 百度图片:    https://image.baidu.com
  8. 可翻页版网址: https://image.baidu.com/search/flip?xxx
  9.  
  10. 使用方法:
  11. search = BaiduImage('上海对外经贸大学')
  12. search.crawler()
  13.  
  14. 图片会保存在: 当前目录/baidu_image_上海对外经贸大学/
  15.  
  16. 其他参数见初始化函数
  17.  
  18. 注:百度图片搜索结果不会产生 404 页,所以搜索第一页总是可下载
  19. """
  20.  
  21.  
  22. from requests_html import HTMLSession
  23. from urllib import parse
  24. import requests_html
  25. import datetime
  26. import hashlib
  27. import sys
  28. import os
  29. import re
  30.  
  31.  
  32. class BaiduImage(object):
  33.  
  34.     def __init__(self, keyword,
  35.                  downdir=None, start=1, maxpage=None,
  36.                  timeout=1, retry=True, maxtry=3):
  37.  
  38.         # keyword: 搜索关键词
  39.         # downdir: 下载图片存放目录,默认为 baidu_image_搜索关键词
  40.         # maxpage: 最大翻页数,默认为 1e8(一直翻页)
  41.         # retry:   是否尝试重新下载失败图片
  42.         # maxtry:  下载失败的图片最大尝试次数
  43.  
  44.         # 其他参数
  45.         # flip_root:   翻页版百度图片搜索基址
  46.         # url_params:  当前网页 URL 数据参数
  47.         # session:     统一 HTML session
  48.         # response:    当前网页 HTML 响应
  49.         # last_urls:   当前页图片链接
  50.         # failed_urls: 爬取失败的网址
  51.         # counter:     已下载的图片计数
  52.  
  53.         self.headers = {
  54.             'Referer': 'https://image.baidu.com'
  55.         }
  56.  
  57.         self.flip_root = r'https://image.baidu.com/search/flip?'
  58.  
  59.         self.keyword = keyword
  60.         self.downdir = downdir
  61.         self.maxpage = maxpage
  62.         self.timeout = timeout
  63.         self.retry = retry
  64.         self.maxtry = maxtry
  65.  
  66.         if downdir is None:
  67.             self.downdir = 'baidu_image_' + keyword
  68.  
  69.         self.url = ''
  70.         self.url_params = {
  71.             'tn': 'baiduimage',
  72.             'ie': 'utf-8',
  73.             'word': self.keyword,
  74.             'pn': (start-1)*20
  75.         }
  76.         self.last_urls = list()
  77.         self.failed_urls = set()
  78.         self.session = HTMLSession()
  79.         self.response: requests_html.HTMLResponse
  80.  
  81.         self.counter = 0
  82.  
  83.         self.make_dir()
  84.  
  85.     def now_time(self):
  86.         return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  87.  
  88.     def make_dir(self):
  89.         try:
  90.             if not os.path.exists(self.downdir):
  91.                 os.mkdir(self.downdir)
  92.             os.chdir(self.downdir)
  93.         except Exception as e:
  94.             print(f'[{self.now_time()}] [ERR - dir] {e}')
  95.             sys.exit(1)
  96.  
  97.     def save_single_image(self, url) -> bool:
  98.         """
  99.        从给定 URL 下载并保存单个图片
  100.        若不能下载,则打印问题 URL 并记录至 self.failed_urls 中
  101.        """
  102.  
  103.         try:
  104.             r = self.session.get(url, headers=self.headers,
  105.                                  timeout=self.timeout)
  106.             r.raise_for_status()
  107.             content = r.content
  108.             filename = hashlib.sha256(content).hexdigest()
  109.             with open(filename+'.jpg', 'wb') as f:
  110.                 f.write(content)
  111.                 print(f'[{self.now_time()}] [INFO - Downloaded] [URL] {url}')
  112.             self.counter += 1
  113.             return True
  114.         except Exception as e:
  115.             self.failed_urls.update([url])
  116.             print(
  117.                 f'[{self.now_time()}] [ERR - Download] [URL] {url} [ERR in Detail] {e}')
  118.             return False
  119.  
  120.     def update_url(self):
  121.         self.url = self.flip_root + parse.urlencode(self.url_params)
  122.  
  123.     def get_page(self):
  124.         """
  125.        获得当前页面 HTML 响应
  126.        """
  127.  
  128.         self.update_url()
  129.  
  130.         try:
  131.             self.response = self.session.get(
  132.                 self.url, headers=self.headers, timeout=self.timeout)
  133.             self.response.raise_for_status()
  134.         except Exception as e:
  135.             print(f'[{self.now_time()}] [ERR - Get Single Page] [ERR in Detail] {e}')
  136.  
  137.     def next_page(self):
  138.         """
  139.        翻页,更新 self.url,若为最后一页则返回 None
  140.        """
  141.  
  142.         self.response.encoding = self.response.apparent_encoding
  143.         if 'class="n"' in self.response.html.html:
  144.             self.url_params['pn'] += 20
  145.             self.update_url()
  146.         else:
  147.             self.url = None
  148.  
  149.     def download_images(self):
  150.         self.get_page()
  151.         html = self.response.html.html
  152.  
  153.         image_urls = re.findall(r'"objURL":"(.*?)"', html)
  154.         for url in image_urls:
  155.             if url not in self.last_urls:
  156.                 self.save_single_image(url)
  157.         self.last_urls = image_urls
  158.  
  159.     def crawler(self):
  160.         # Dirty: 如果未设置 self.maxpage,则用大数模拟无尽循环
  161.  
  162.         self.maxpage = self.maxpage if self.maxpage is not None else 10**8
  163.         for _ in range(self.maxpage):
  164.             self.download_images()
  165.             self.next_page()
  166.             if self.url is None:
  167.                 break
  168.  
  169.         # 尝试重下失败列表中的图片
  170.         if self.retry:
  171.             print(f'[{self.now_time()}] [INFO] 尝试下载之前下载失败的图片...')
  172.             print(self.failed_urls)
  173.             for _ in range(self.maxtry):
  174.                 new_failed_urls = self.failed_urls.copy()
  175.                 for url in new_failed_urls:
  176.                     if self.save_single_image(url):
  177.                         self.failed_urls.remove(url)
  178.  
  179.         print(f'[{self.now_time()}] [INFO] 结束. 共下载 {self.counter} 张图片.')
  180.  
  181.  
  182. if __name__ == '__main__':
  183.     search = BaiduImage('上海对外经贸大学', start=1, maxpage=1)
  184.     search.crawler()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement