请选择 进入手机版 | 继续访问电脑版
快捷导航
【27报网:爬虫福利之一爬27报网MM】刚学爬虫花了4个小时写的,每一步备注的都很清楚,喜欢的朋友自己可以研究研究......
目标网站:https://www.27bao.com
环境:Python3.x
相关第三方模块:requests、lxml
Re:各位在测试时只需要将__init__下的 self.path 属性指定为你当前系统要保存的路径,使用 python xxx.py 即可运行。
源码如下:
  1. import os
  2. import time
  3. import requests
  4. from lxml import etree
  5. class MeiZiSpider(object):
  6.     """27 bao website MM spider"""
  7.     def __init__(self):
  8.         self.base_url = 'https://www.27bao.com/meinv/list_1.html'
  9.         # self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"}
  10.         self.headers = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'}
  11.         # 构建url的前缀
  12.         self.url_prefix = 'https://www.27bao.com'
  13.         # 构建第二层url的前缀
  14.         self.inner_url_prefix = 'https://www.27bao.com/meinv/'
  15.         # 构建点开每个美女内部的所有url
  16.         self.inner_url = 'https://www.27bao.com/meinv/56870_{}.html'
  17.         # 文件保存的路径
  18.         # linux路径
  19.         # self.path = '/home/python/Desktop/27baomeimei/'
  20.         # windows路径
  21.         self.path = 'C:/Users/Nick/Desktop/27baomeimei/'
  22.     def send_first_req(self):
  23.         """发送第一层请求,返回首页响应的html内容"""
  24.         html_str = requests.get(self.base_url, headers=self.headers).content.decode()
  25.         return html_str
  26.     def get_total_page(self):
  27.         """获取网站美女图片总页数"""
  28.         # 模拟发送请求, 返回响应数据(便于提取总页数)
  29.         html_str = self.send_first_req()
  30.         # 将返回的 html字符串 转换为 element对象
  31.         element_obj = etree.HTML(html_str)
  32.         # 提取末页的url, 再切片提取最大页数
  33.         total_page = element_obj.xpath('//*[@id="pages"]/a[9]/@href')[0].split('_')[-1].split('.')[0]
  34.         print('========该网站美女图片目前共有 {} 页========'.format(total_page))
  35.         return total_page
  36.     def get_each_girl_url(self, each_page_url):
  37.         """第一层解析 ---> 获取每一页每个女孩的url"""
  38.         # 用于存放拼接后每个女孩的url
  39.         girl_url_list = []
  40.         # 模拟发送请求, 返回响应数据(便于提取url)
  41.         html_str = self.send_request(each_page_url)
  42.         # 将返回的 html字符串 转换为 element对象
  43.         element_obj = etree.HTML(html_str)
  44.         # 提取所有url后缀  ---> 列表
  45.         url_postfix = element_obj.xpath('/html/body/div[2]/div[2]/ul/li/a/@href')
  46.         # 提取每个妹妹的标题, 便于后面命名
  47.         url_title_li = element_obj.xpath('/html/body/div[2]/div[2]/ul/li/p/a/text()')
  48.         # 遍历提取的url列表, 拼接完整的url, 并保存列表中
  49.         for url in url_postfix:
  50.             # 添加拼接后的url到列表
  51.             girl_url_list.append(self.url_prefix + url)
  52.         # print(girl_url_list)
  53.         title_and_url_li = list(zip(url_title_li, girl_url_list))
  54.         # print(title_and_url_li)
  55.         return title_and_url_li
  56.     def send_request(self, url):
  57.         """发送第二层请求,返回响应的html内容"""
  58.         # print(url)
  59.         try:
  60.             response = requests.get(url, headers=self.headers, timeout=5)
  61.         except:
  62.             return None
  63.         # html_str = response.content.decode()
  64.         html_str = response.content
  65.         return html_str
  66.     def parse_data(self, html_str):
  67.         """第二层解析 ---> 获取当前女孩的每个url"""
  68.         # 将返回的 html字符串 转换为 element对象
  69.         element_obj = etree.HTML(html_str)
  70.         each_image = element_obj.xpath('/html/body/div[3]/center/img/@src')[0]
  71.         # print(each_image)
  72.         return each_image
  73.     def save_file(self, image_data, title, image_name):
  74.         # 如果目录不存在, 就新建
  75.         if not os.path.exists(self.path + title):
  76.             os.makedirs(self.path + title)
  77.         # 切换到新建目录下
  78.         os.chdir(self.path + title)
  79.         # for i in range(1, int(total_page) + 1):
  80.         #     image_name = str(i) + '.jpg'
  81.         with open(image_name, 'wb') as f:
  82.             f.write(image_data)
  83.     def download(self):
  84.         total_page = self.get_total_page()
  85.         # 开循环, 爬取每个页面的每个妹妹的所有图片
  86.         for page in range(1, int(total_page) + 1):
  87.             print('\n正在爬取第 {} 页...\n'.format(page))
  88.             # 构建每一页的url
  89.             each_page_url = 'https://www.27bao.com/meinv/list_{}.html'.format(page)
  90.             title_and_url_li = self.get_each_girl_url(each_page_url)
  91.             # 遍历获取每个妹妹的总url
  92.             for girl_url in title_and_url_li:
  93.                 # print(girl_url[1])
  94.                 # image_list = []
  95.                 html_str = self.send_request(girl_url[1])
  96.                 print('正在爬取的地址: {}'.format(girl_url[1]))
  97.                 # 获取目前爬取的美女内部总页数
  98.                 inner_total_page = etree.HTML(html_str).xpath('//*[@id="pages"]/a[last()-1]/text()')[0]
  99.                 print('\n目前爬取的美女图片共有 {} 张\n'.format(inner_total_page))
  100.                 # 循环并构造每一张图片的url, 请求, 解析, 并保存
  101.                 image_data = None
  102.                 for inner_page in range(1, int(inner_total_page) + 1):
  103.                     print('正在爬取 {} 第 {} 张图片...'.format(girl_url[0], inner_page))
  104.                     # 构造第二页以后的每个url
  105.                     each_image_url = girl_url[1].split('.html')[0] + '_{}.html'
  106.                     if inner_page == 1:
  107.                         # 获取第一页的url, 因为第一页和其他页的规律不一样,所以这里单独出来
  108.                         each_image_url = self.parse_data(html_str)
  109.                         # html_str = self.send_request(each_image_url)
  110.                         image_data = self.send_request(each_image_url)
  111.                     else:
  112.                         each_image_url = each_image_url.format(inner_page)
  113.                         # print(each_image_url)
  114.                         html_str = self.send_request(each_image_url)
  115.                         image = self.parse_data(html_str)
  116.                         image_data = self.send_request(image)
  117.                     # 如果请求图片的url在5秒之内无响应, 立即终止当前妹妹所有url的循环
  118.                     if image_data is None:
  119.                         print('当前MM的url无响应,正在跳转到下一个MM的url\n')
  120.                         break
  121.                     # 拼接保存图片的名称
  122.                     image_name = str(inner_page) + '.jpg'
  123.                     try:
  124.                         # 切换图片保存目录
  125.                         os.chdir(self.path + girl_url[0])
  126.                         # 判断文件是否存在, 存在则不再保存, 跳过
  127.                         if os.path.exists(image_name):
  128.                             print('第 {} 张已保存, 跳过...'.format(inner_page))
  129.                             continue
  130.                     except Exception as e:
  131.                         print('目录 {} 不存在, 正在新建...'.format(e))
  132.                     # 保存图片到本地
  133.                     self.save_file(image_data, girl_url[0], image_name)
  134.                     # image_list.append(image)
  135.                 # print(image_list)
  136.                 if image_data:
  137.                     print('\n{} 的所有图片已全部爬取完毕...\n'.format(girl_url[0]))
  138.                 # 休眠5秒中, 避免请求一直处于长连接导致ip被封
  139.                 time.sleep(10)
  140. if __name__ == '__main__':
  141.     MeiZiSpider().download()
复制代码


举报 使用道具
| 回复

共 0 个关于本帖的回复 最后回复于 2019-10-16 16:03

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

精选推荐

  • 2019微信域名防封指南,独家分享!2019微信域名防封指南,独家分享!
  • 微信网址强制跳转浏览器打开源码微信网址强制跳转浏览器打开源码
  • 【独家】无需备案域名和认证公众号调用微信分享JS-SDK代码,微信强制分享源码【独家】无需备案域名和认证公众号调用微信
  • 微信裂变营销系统重磅上线,助力微信营销!微信裂变营销系统重磅上线,助力微信营销!
  • 专家详解:什么是微信二级不死域名?专家详解:什么是微信二级不死域名?

热门排行

快速回复 返回列表

小黑屋|微信论坛  |网站地图

GMT+8, 2019-11-13 20:24 , Processed in 0.070481 second(s), 34 queries .