Python3+scrapy+selenium+BaiduAI识别并下载花瓣网高颜值妹子图片

一、说明

1.1 背景说明

上周在“Python3使用百度人脸识别接口识别高颜值妹子图片”中自己说到在成功判断颜值后,下截图片并不是什么难点。

直观感觉上确实如此,你判断的这个url适不适合下载,适合我就去下不适合就不去下,这算什么难点呢。

但事实经常没有想象的那么简单,所以决定去验证一下。结果再次证实自己想简单了,程序的编写和调试花了一周的业余时间,好在总算完成了。

1.2 程序编写过程说明

我以花瓣网http://huaban.com/favorite/beauty/入手,首先确定从beauty这个页面提取形如http://huaban.com/pins/1715655164/的浏览页面(//a/@herf),在这类界面中才真正提取图片src(//img/@src),然后将src提交到百度AI人脸识别接口,如果返回的颜值达标就下载;如果不达标就跳过。

第一个遇到的问题是ImagesPipeline找不到PIL,那就安装PIL,但PyCharm中安装PIL提示没有与当前python匹配的版本;然后自接用conda安装,最后看到环境中的python3.6直接被降成了python2.7,程序报了很多错,百度发现PIL只支持到Python2.7,Python3要安装Pillow,重新配置环境安装Pillow这个问题算处理了。

第二个遇到的问题是ImagesPipeline下载报错,再百度网上说PIL处理压缩图片有问题;ImagesPipeline也就是针对收到的url下载图片面已,自己写个保存函数(程序中的save_image)这个问题也就处理了,但这是有打击的因为我断言的“下载图片Scrapy的ImagesPipeline是绝配”太自以为然了

第三个遇到的问题是花瓣网不是直接整个返回页面,而是使用ajax取回各种元素再构造出的页面;ajax网上看了一般说用selenium处理,好那就去研究

第四个遇到的问题在下拉几个页面后花瓣网要求登录;首先考虑的是借助scrapy的FormRequest.from_response()取回Set-Cookie然后加到selenium的Cookie中去,但后来又想我分明selenium自己可以登录为什么要再多用个FormRequest.from_response()来取Cookie这么麻烦,所以登录这个问题也用selenium处理了

第五个问题是要模拟人看完一页才下拉滚动条加载下一页,异步加载相当于在上一页的后面追加,这样造成的问题是当前抽取出来的浏览页面包含了之前已经加载的所有的浏览页面,由于没有了scrapy我们如何去避免这里的重复问题;这个问题我这里的处理办法是使用for i in range(5):模拟五次异步加载,然后使用viewed_page_count这个变量记录之前异步加载已抽取的浏览页面数量,本次遍历从image_view_page_urls[viewed_page_count]开始(这种处理办法正确的前提是Seletor抽取浏览页面是严格从头向尾抽取的,这我并不确定但应该来说很大可能是这样)

第六个遇到的问题是http://huaban.com/favorite/beauty/,这个界面因为要下拉滚动条异步加载下一页所以这个界面应该保存,而http://huaban.com/pins/1715655164/这些链接需要不断打开,selenium又不支持多选项卡只用selenium构造一个浏览器是不够的;这个问题的处理办法是构造一个浏览器不够,那就构造两个浏览器

第七个遇到的问题是程序跑了大半个小时识别了很多符合下载条件的图片但都还没有下载任何一张图片;这个问题思路是降低程序的复杂度,首先花瓣网是用瀑布流形式的就http://huaban.com/favorite/beauty/一个页面,并不需要爬行所以直接使用Spider而不使用CrawlSpider这样可以去掉Rule;但依然还是没有下载,追踪了半天也没弄清楚不进入下载的原因,又一想既然我不用爬行那Spider的在程序并没有启什么作用而且其导致了我不清楚为什么没有下载图片。所以没有开始下载图片这个问题以弃用scrapy进行处理(我的“下载图片Scrapy的ImagesPipeline是绝配”彻底被否定了)

当然就功能实现来说是有一些捷径可以走的,比如首选登录这个问题如果通过修改User-Agent伪装成手机浏览器是不需要登录的。再比如瀑布流网站异步加载,直接找到ajax接口访问从返回的json内容中就可以提取接链接,或者调大limit一次就可以获取更多的返回结果,并不需要真去下拉滚动条。但,我们就是要正面硬刚,奇技淫巧是不要的。

程序的流程是:

login_in()登录花瓣网

open_main_page()手动重定向到http://huaban.com/favorite/beauty/

在open_main_page()中使用for i in range(5):模拟用户五次下拉滚动条到底部

在for i in range(5):内每次都抽取新加载的浏览页面交给get_img_url_page()获取图片的src

get_img_url_page()将src传到BaiduFaceIdentify进行鉴别,如果评分超过50分就将src传到save_image()保存图片,如果不达标则跳过

1.3 程序运行结果展示

运行输出:

下载图片(我们是在认真地探讨技术,图片这种东西长什么样我根本没注意,我这么说你相信的吧(>_<))

文件夹:

二、程序源代码

使用时三件事:

1) 将以下两个文件保存在同级目录然后建个pic目录

2) huaban.py找到self.browser_main_page.find_element_by_name(‘email‘).send_keys(‘[email protected]‘)修改成自己花瓣网的用户名密码

3)BaiduFaceIdentify.py找到将client_id赋值成自己的API Key,client_secret赋值成自己的Secret Key

2.1 主程序----huaban.py

使用时,记得找到self.browser_main_page.find_element_by_name(‘email‘).send_keys(‘[email protected]‘)修改成自己的用户名密码

import re
import time
import logging
import urllib.request
from scrapy import Selector
from selenium import webdriver
from BaiduFaceIdentify import BaiduFaceIdentify

class HuabanDownloader():
    # 初始化函数
    def __init__(self):
        # 百度识别实例
        self.bfi = BaiduFaceIdentify()
        # 用于打开view_page的浏览器
        self.browser_view_page = webdriver.Firefox()
        self.browser_view_page.set_page_load_timeout(10)
        # 用于打开main_page的浏览器
        self.browser_main_page = webdriver.Firefox()
        self.browser_main_page.set_page_load_timeout(20)

    # 此函数用于登录花瓣网
    def login_in(self):
        try:
            # main_page浏览器打开花瓣网,以准备登录
            self.browser_main_page.get(‘http://huaban.com/‘)
        except Exception:
            # 如果到时间还没加载完成那就终止还没完成的加载,直接进行后续步骤
            self.browser_main_page.execute_script(‘window.stop()‘)
        # 点击登录按钮,唤出登录对话框
        self.browser_main_page.find_element_by_css_selector(‘.login‘).click()
        # 填写用户名,改成自己的用户名,我贴上来时乱改的
        self.browser_main_page.find_element_by_name(‘email‘).send_keys(‘[email protected]‘)
        # 填写密码,改成自己的密码,我贴上来时乱改的
        self.browser_main_page.find_element_by_name(‘password‘).send_keys(‘yourpassword‘)
        # 点击登录
        self.browser_main_page.find_element_by_css_selector(‘a.btn:nth-child(4)‘).click()
        time.sleep(2)

    # 此函数负责打开main_page
    def open_main_page(self,main_page_url):
        # viewed_page_count保存上次异步加载返回的self.browser_main_page.page_source中已有的view_page数量
        viewed_page_count = 0
        try:
            # 登录后,手动重定向到main_page
            self.browser_main_page.get(main_page_url)
        except Exception:
            # 如果到时间还没加载完成那就终止还没完成的加载,直接进行后续步骤
            self.browser_main_page.execute_script(‘window.stop()‘)
        # 这个for模拟用户五次将浏览器滚动条拉到了底部(即五次触发加载下一页的ajax)
        # 五次可以爬半天
        for i in range(5):
            try:
                # 浏览器滚动条拉到底部
                self.browser_main_page.execute_script("window.scrollTo(0,document.body.scrollHeight)")
            except Exception:
                # 如果到时间还没加载完成那就终止还没完成的加载,直接进行后续步骤
                self.browser_main_page.execute_script(‘window.stop()‘)
            # 获取当前浏览器界面的html源代码
            content = self.browser_main_page.page_source
            # 将html源代码传到选择器
            sel = Selector(text=content)
            # 使用选择器抽取出浏览页面
            image_view_page_urls = sel.xpath(‘//a/@href‘).extract()
            # 遍历浏览页面
            for image_view_page_url in image_view_page_urls[viewed_page_count:]:
                # 匹配pins+6位以上数字形式的连接才是我们想访问浏览页面
                # 如果匹配那么传到get_img_url_from_view_page()去抽取图片src
                if re.search(‘pins/\d{6,}‘,image_view_page_url):
                    logging.warning(‘view_page url格式匹配,即将进入:‘ + image_view_page_url)
                    image_view_page_url_temp = ‘http://huaban.com‘ + image_view_page_url
                    self.get_img_url_from_view_page(image_view_page_url_temp)
                # 如果不匹配那么跳过
                else:
                    logging.warning(‘view_page url格式不匹配,将不进入:‘+ image_view_page_url)
            # 记录本次self.browser_main_page.page_source中已有的view_page数量
            viewed_page_count = len(image_view_page_urls)

    # 此函数负责从view_page中抽取图片src,并将本次view_page的所有src传到百度识别接口,获取检测结果
    def get_img_url_from_view_page(self, image_view_page_url):
        try:
            # view_page浏览器打开传来的view_page
            self.browser_view_page.get(image_view_page_url)
        except Exception:
            # 如果到时间还没加载完成那就终止还没完成的加载,直接进行后续步骤
            self.browser_view_page.execute_script(‘window.stop()‘)
        content = self.browser_view_page.page_source.encode(‘utf-8‘)
        sel = Selector(text=content)
        # 从view_page中抽取图片src
        img_urls = sel.xpath(‘//img/@src‘).extract()

        for img_url in img_urls:
            # 排除gif及确保图片不是网站相对图径
            if ‘gif‘ not in img_url and ‘aicdn.com‘ in img_url:
                logging.warning(‘\r\nimg_url格式匹配,即将调用百度识别:http:‘ + img_url)
                img_url_tmp = ‘http:‘ + img_url[:img_url.find(‘_‘)]
                try:
                    # 调用百度识别接口进行识别,当然这个接口是我们自己封装的BaiduFaceIdentify类
                    beauty_value = self.bfi.parse_face_pic(img_url_tmp)
                except Exception:
                    logging.error(‘百度识别遇到了一下错误:‘ + img_url_tmp)
                    continue
                # 对返回的颜值进行判断,以决定如何处理图片
                if beauty_value > 50.0:
                    logging.warning(‘颜值‘ + str(beauty_value) +‘达标,准备保存该图片:‘ + img_url_tmp)
                    self.save_image(img_url_tmp, beauty_value)
                elif beauty_value == 1.0:
                    logging.warning(‘不是妹子,跳过该图片:‘ + img_url_tmp)
                elif beauty_value == 0.0:
                    logging.warning(‘没有人脸,跳过该图片:‘ + img_url_tmp)
                else:
                    logging.warning(‘颜值‘ + str(beauty_value) +‘过低,跳过该图片:‘ + img_url_tmp)
            else:
                logging.warning(‘img_url格式不匹配,将不调用百度识别:http‘ + img_url)

    # 此函数用于保存颜值达标的图片到本地硬盘
    def save_image(self, img_url,beauty_value):
        # 图片名称使用“颜值”-“下载日期”形式
        image_name = str(beauty_value) + ‘-‘ + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ‘.jpg‘
        # 保存图片
        urllib.request.urlretrieve(img_url, ‘pic\\‘ + image_name)

    # 此函数负责在程序退出时将两个浏览器关闭
    def __del__(self):
        self.browser_view_page.close()
        self.browser_main_page.close()

if __name__ == ‘__main__‘:
    main_page_url = ‘http://huaban.com/favorite/beauty/‘
    huaban_downloader = HuabanDownloader()
    huaban_downloader.login_in()
    huaban_downloader.open_main_page(main_page_url)

2.2 百度识别接口----BaiduFaceIdentify.py

import base64
import urllib
import requests
import json
import logging

class BaiduFaceIdentify():
    #此函数用于获取access_token,返回access_token的值
    #此函数被parse_face_pic调用
    def get_access_token(self):
        client_id = ‘KuLRFhTzX3zBFBSrbQBsl6Q4‘                #此变量赋值成自己API Key的值
        client_secret = ‘8ahbIb2hEOePzXhehw9ZDL9kGvbzIHTU‘    #此变量赋值成自己Secret Key的值
        auth_url = ‘https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=‘ + client_id + ‘&client_secret=‘ + client_secret

        response_at = requests.get(auth_url)
        json_result = json.loads(response_at.text)
        access_token = json_result[‘access_token‘]
        return access_token

    #此函数进行人脸识别,返回识别到的人脸列表
    #此函数被parse_face_pic调用
    def identify_faces(self,url_pic,url_fi):
        headers = {
            ‘Content-Type‘ : ‘application/json; charset=UTF-8‘
        }
        # 因为提交URL让baidu去读取图片,总是返回图片下载错了
        # 所以我们这里将读取URL指向的图片,将图片转成BASE64编码,改用提交BASE64编码而不是提交URL
        pic_obj = urllib.request.urlopen(url_pic)
        pic_base64 = base64.b64encode(pic_obj.read())
        post_data = {
            # ‘image‘: url_pic,
            # ‘image_type‘ : ‘URL‘,
            ‘image‘: pic_base64,
            ‘image_type‘: ‘BASE64‘,
            ‘face_field‘ : ‘facetype,gender,age,beauty‘, #expression,faceshape,landmark,race,quality,glasses
            ‘max_face_num‘: 1
        }

        response_fi = requests.post(url_fi,headers=headers,data=post_data)
        json_fi_result = json.loads(response_fi.text)
        # 有些图片是没有人脸的,或者识别有问题,这个我们不细管直接捕获异常就返回空列表
        try:
            # if json_fi_result[‘result‘] is None:
            #     return []
            # else:
                return json_fi_result[‘result‘][‘face_list‘]
        except Exception:
            return []
        #下边的print也许是最直观,你最想要的
        #print(json_fi_result[‘result‘][‘face_list‘][0][‘age‘])
        #print(json_fi_result[‘result‘][‘face_list‘][0][‘beauty‘])

    #此函数用于解析进行人脸图片,返回图片中人物颜值
    #此函数调用get_access_token、identify_faces
    def parse_face_pic(self,url_pic):
        #调用get_access_token获取access_token
        access_token = self.get_access_token()
        # access_token = ‘24.1c602a1fc8adbb9edc82d3bee89b229a.2592000.1532370445.282335-11407672‘
        url_fi = ‘https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=‘ + access_token
        #调用identify_faces,获取人脸列表
        json_faces = self.identify_faces(url_pic,url_fi)
        # 如果没有人脸,那么就以0.0为颜值评分返回
        if len(json_faces) == 0:
            # logging.warning(‘未识别到人脸‘)
            return 0.0
        else:
            for json_face in json_faces:
                logging.debug(‘种类:‘+json_face[‘face_type‘][‘type‘])
                logging.debug(‘性别:‘+json_face[‘gender‘][‘type‘])
                logging.debug(‘年龄:‘+str(json_face[‘age‘]))
                logging.debug(‘颜值:‘+str(json_face[‘beauty‘]))
                # 如果识别到的不是妹子,也以1.0为颜值评分返回
                # 如果识别到的是妹子,直接以值颜值返回
                if json_face[‘gender‘][‘type‘] != ‘female‘:
                    # logging.info(‘图片不是妹子‘)
                    return 1.0
                else:
                    return json_face[‘beauty‘]

if __name__ == ‘__main__‘:
    #uil_pic赋值成自己要测试的图片的url地址
    url_pic = ‘https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1357154930,886228461&fm=27&gp=0.jpg‘
    bfi = BaiduFaceIdentify()
    bfi.parse_face_pic(url_pic)

import base64import urllibimport requestsimport jsonimport logging

class BaiduFaceIdentify():    #此函数用于获取access_token,返回access_token的值    #此函数被parse_face_pic调用def get_access_token(self):        client_id = ‘KuLRFhTzX3zBFBSrbQBsl6Q4‘                #此变量赋值成自己API Key的值client_secret = ‘8ahbIb2hEOePzXhehw9ZDL9kGvbzIHTU‘    #此变量赋值成自己Secret Key的值auth_url = ‘https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=‘ + client_id + ‘&client_secret=‘ + client_secret

response_at = requests.get(auth_url)        json_result = json.loads(response_at.text)        access_token = json_result[‘access_token‘]        return access_token

#此函数进行人脸识别,返回识别到的人脸列表    #此函数被parse_face_pic调用def identify_faces(self,url_pic,url_fi):        headers = {            ‘Content-Type‘ : ‘application/json; charset=UTF-8‘}        # 因为提交URL让baidu去读取图片,总是返回图片下载错了        # 所以我们这里将读取URL指向的图片,将图片转成BASE64编码,改用提交BASE64编码而不是提交URLpic_obj = urllib.request.urlopen(url_pic)        pic_base64 = base64.b64encode(pic_obj.read())        post_data = {            # ‘image‘: url_pic,            # ‘image_type‘ : ‘URL‘,‘image‘: pic_base64,‘image_type‘: ‘BASE64‘,‘face_field‘ : ‘facetype,gender,age,beauty‘, #expression,faceshape,landmark,race,quality,glasses‘max_face_num‘: 1}

response_fi = requests.post(url_fi,headers=headers,data=post_data)        json_fi_result = json.loads(response_fi.text)        # 有些图片是没有人脸的,或者识别有问题,这个我们不细管直接捕获异常就返回空列表try:            # if json_fi_result[‘result‘] is None:            #     return []            # else:return json_fi_result[‘result‘][‘face_list‘]        except Exception:            return []        #下边的print也许是最直观,你最想要的        #print(json_fi_result[‘result‘][‘face_list‘][0][‘age‘])        #print(json_fi_result[‘result‘][‘face_list‘][0][‘beauty‘])

#此函数用于解析进行人脸图片,返回图片中人物颜值    #此函数调用get_access_token、identify_facesdef parse_face_pic(self,url_pic):        #调用get_access_token获取access_token        # access_token = self.get_access_token()access_token = ‘24.1c602a1fc8adbb9edc82d3bee89b229a.2592000.1532370445.282335-11407672‘url_fi = ‘https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=‘ + access_token        #调用identify_faces,获取人脸列表json_faces = self.identify_faces(url_pic,url_fi)        # 如果没有人脸,那么就以0.0为颜值评分返回if len(json_faces) == 0:            # logging.warning(‘未识别到人脸‘)return 0.0else:            for json_face in json_faces:                logging.debug(‘种类:‘+json_face[‘face_type‘][‘type‘])                logging.debug(‘性别:‘+json_face[‘gender‘][‘type‘])                logging.debug(‘年龄:‘+str(json_face[‘age‘]))                logging.debug(‘颜值:‘+str(json_face[‘beauty‘]))                # 如果识别到的不是妹子,也以1.0为颜值评分返回                # 如果识别到的是妹子,直接以值颜值返回if json_face[‘gender‘][‘type‘] != ‘female‘:                    # logging.info(‘图片不是妹子‘)return 1.0else:                    return json_face[‘beauty‘]

if __name__ == ‘__main__‘:    #uil_pic赋值成自己要测试的图片的url地址url_pic = ‘https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1357154930,886228461&fm=27&gp=0.jpg‘bfi = BaiduFaceIdentify()    bfi.parse_face_pic(url_pic)

原文地址:https://www.cnblogs.com/lsdb/p/9221095.html

时间: 2024-11-06 03:40:24

Python3+scrapy+selenium+BaiduAI识别并下载花瓣网高颜值妹子图片的相关文章

Python3使用百度人脸识别接口识别高颜值妹子图片

一.在百度云平台创建应用 为什么要到百度云平台创建应用,首先来说是为了获取获取access_token时需要的API Key和Secret Key 至于为什么需要API Key和Secret Key才能获取access_token,应该一是为了推广一下百度云二是为了获取一些统计数据.微信苹果要你们搞得,度娘就不能要你们搞得?不要纠结 1.访问百度AI开放 平台:http://ai.baidu.com/ 2."产品服务"----"人脸检测" 3. "立即使用

ubuntu16.04 python3 安装selenium及环境配置

环境 ubuntu16.04 python3 安装selenium sudo pip3 install seleium 默认安装完是支持firefox,但是更新得太慢对于较新的firefox已经不支持了,需要安装geckodriver,地址 https://github.com/mozilla/geckodriver/releases/ 下载完后解压然后在终端中cd到下载文件路径下,下面以路径为下载为例 依次执行以下命令: 安装xvfb sudo apt-get install xvfb 安装p

Python3.x:如何识别图片上的文字

Python3.x:如何识别图片上的文字 一.安装第三方库(pillow.pytesseract) pip install pillow pip install pytesseract 二.安装识别引擎tesseract-ocr 下载地址(解压安装): 原文地址:https://www.cnblogs.com/lizm166/p/8331398.html

Python3.x:pytesseract识别率提高(样本训练)

Python3.x:pytesseract识别率提高(样本训练) 1,下载并安装3.05版本的tesseract 地址:https://sourceforge.net/projects/tesseract-ocr/ 2,如果你的训练素材是很多张非tif格式的图片,首先要做的事情就是将这么图片合并(个人觉得素材越多,基本每个字母和数字都覆盖了训练出来的识别率比较好) 下载这个工具:VietOCR.NET-3.3.zip 地址:http://sourceforge.net/projects/viet

python3写的腾讯漫画下载器

代码很稀烂,开坑后一个月的时间,断断续续总算是写完了,主体功能完成,顺便PYQT5写了个GUI,并用cx_freeze打包,可以在windows下用. 项目托管在github: https://github.com/abcfy2/getComic 预览效果 放几张预览图,支持不连续的章节选择下载. windows下的效果: deepin下效果: 算法描述 腾讯的漫画从PC版访问时看到的是flash,但是移动版的页面却是图片,用ipad的UA请求ac.qq.com可以发现跳转为m.ac.qq.co

通过scrapy内置的ImagePipeline下载图片到本地

1.通过scrapy内置的ImagePipeline下载图片到本地 1.通过scrapy内置的ImagePipeline下载图片到本地 1)在settings.py中打开 ITEM_PIPELINES 的注释,在  ITEM_PIPELINES 中加入 ITEM_PIPELINES = { 'spider_first.pipelines.SpiderFirstPipeline': 300, 'scrapy.pipelines.images.ImagesPipeline':5, #后面的数字代表执

python3、selenium、autoit3,通过flash控件上传文件

autoit.au3 #include <Constants.au3> WinWait("打开","",20); //暂停执行脚本,直到上传对话框出现 WinActive("打开") WinWaitActive("打开","",5); //激活上传窗口 ControlFocus("打开", "", "[CLASS:Edit; INSTANCE:1

使用scrapy爬虫,爬取今日头条首页推荐新闻(scrapy+selenium+PhantomJS)

爬取今日头条https://www.toutiao.com/首页推荐的新闻,打开网址得到如下界面 查看源代码你会发现 全是js代码,说明今日头条的内容是通过js动态生成的. 用火狐浏览器F12查看得知 得到了今日头条的推荐新闻的接口地址:https://www.toutiao.com/api/pc/focus/ 单独访问这个地址得到 此接口得到的数据格式为json数据 我们用scrapy+selenium+PhantomJS的方式获取今日头条推荐的内容 下面是是scrapy中最核心的代码,位于s

python3 引入selenium库报错ModuleNotFoundError: No module named &#39;selenium&#39;

解决方法: pip install -U selenium python3 引入selenium库报错ModuleNotFoundError: No module named 'selenium' 原文地址:https://www.cnblogs.com/zouke1220/p/9326434.html