都 “3202”年了还用 selemunim ?教你使用 scrapy + DrissionPage 爬取51job 和 过滑块验证码

前言

  • 一、DrissionPage 是什么?
  • 二、scrapy + DeissionPage 爬取51 job 
  • 1.创建scrapy 项目
  • 2. 重写 middewares.py 
  • 3. 编写 a_51job.py
  • 总结

前言

在爬取网站数据,往往会碰到一些加密的数据或者各种各样的验证码,可是 直接使用 request 需要js 逆向耗费大量时间,但使用 selemunim 等自动化工具又很容易被识别。哪有没有一种折中的办法既可以有request 请求的速度又有selemunim 的简单的操作?或许DrissionPage 可以帮助你


一、DrissionPage 是什么?

概述:DrissionPage 是一个基于 python 的网页自动化工具。它既能控制浏览器,也能收发数据包,还能把两者合而为一。可兼顾浏览器自动化的便利性和 requests 的高效率。它功能强大,内置无数人性化设计和便捷功能。它的语法简洁而优雅,代码量少,对新手友好。

本库采用全自研的内核,内置了 N 多实用功能,对常用功能作了整合和优化,对比 selenium,有以下优点:

  • 无 webdriver 特征
  • 无需为不同版本的浏览器下载不同的驱动
  • 运行速度更快
  • 可以跨 iframe 查找元素,无需切入切出
  • 把 iframe 看作普通元素,获取后可直接在其中查找元素,逻辑更清晰
  • 可以同时操作浏览器中的多个标签页,即使标签页为非激活状态,无需切换
  • 可以直接读取浏览器缓存来保存图片,无需用 GUI 点击另存
  • 可以对整个网页截图,包括视口外的部分(90以上版本浏览器支持)
  • 可处理非open状态的 shadow-root

更多用法和概述不在此在说明,详细用法点击这里

二、scrapy + DeissionPage 爬取51 job 

准备工具:

pycharm 3.7

scrapy 2.9.0

DrissionPage 3.2.30

1.创建scrapy 项目

在pycharm 终端依次输入:

scrapy startproject _51job
cd _51job
scrapy genspider a_51job www.51job.com 

创建好的文件如下:

都 “3202”年了还用 selemunim ?教你使用 scrapy + DrissionPage 爬取51job 和 过滑块验证码_第1张图片

2. 重写 middewares.py 

因为 scrapy 是使用 request 发送请求的,因此需要重写中间件来使用DrissionPage

class DrissionPageMiddleware:

    def process_request(self, request, spider):
        """
        使用 Drissonpage 请求
        :param request:
        :param spider:
        :return:
        """
        url = request.url
        spider.edge.get(url) # 请求页面,和selemunim get方法一致
        spider.edge.wait.load_start(3)  # 等待加载
        html = spider.edge.html # 获取页面 html,和selemunim的 source 属性一致
        return HtmlResponse(url=url, body=html, request=request, encoding='utf-8')

    def process_response(self, request, response, spider):
        """
        处理滑块验证码
        :param request:
        :param response:
        :param spider:
        :return:
        """
        url = request.url
        from DrissionPage.common import ActionChains
        while spider.edge.s_ele('#nc_1_n1z'):  # 出现滑块验证码
            spider.edge.clear_cache()  # 清理缓存
            ac = ActionChains(spider.edge) 
            for i in range(random.randint(10, 20)):
                ac.move(random.randint(-20, 20), random.randint(-10, 10))
            else:
                ac.move_to('#nc_1_n1z')
            ac.hold().move(300) 
            time.sleep(2)
            spider.edge.get(url)
            time.sleep(2)
            html = spider.edge.html
            if not '滑动验证页面' in html:  # 验证成功
                return HtmlResponse(url=url, body=html, request=request, encoding='utf-8')
            else:  # 验证失败
                spider.edge.clear_cache()
                spider.edge.get(url)
        return response

3. 编写 a_51job.py

import time
import scrapy
from DrissionPage import ChromiumPage
import random
from DrissionPage.errors import ElementNotFoundError


class A51jobSpider(scrapy.Spider):
    name = "_51job"
    # allowed_domains = ["www.51job.com"]
    start_urls = []  # 搜索链接 如:https://we.51job.com/pc/searchjobArea=190200&keyword=java&searchType=2&sortType=0&metro=

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.edge = ChromiumPage() # 实例化浏览器
        self.all_urls = []
        self.isdatail = False  # 搜索页基本信息
        self.isbasic = True  # 详细页信息

    def get_all_want_info(self, response):
        """
        获取所有的招聘信息
        :return:
        """
        last_page = int(self.edge.eles('.number')[-1].text)  # 搜索页总页数
        for page_num in range(1, last_page + 1):  # 翻页
            print(f'------正在爬取第{page_num}页--------')
            self.edge.ele('#jump_page').input(page_num) # 输入页码
            self.edge.ele('.jumpPage').click() # 点击跳转
            time.sleep(3)
            # 获取招聘基本信息
            if self.isbasic:
                page_want_info = []
                job_names = self.edge.s_eles('.jname at')  # 职业名称
                times = self.edge.s_eles('.time')  # 发布时间
                sals = self.edge.s_eles('.sal')  # 薪资
                requrire = self.edge.s_eles('.d at')  # 招聘要求
                tags = self.edge.s_eles('.tags')  # 福利
                company_names = self.edge.s_eles('.cname at')  # 公司
                company_class = self.edge.s_eles('.dc at')  # 公司类别
                domain_class = self.edge.s_eles('.int at')  # 领域
                for base_want_info in zip(company_names, job_names, times, sals, tags, requrire, company_class,
                                          domain_class):
                    want_info = []
                    for i in base_want_info:
                        want_info.append(i.text)
                    page_want_info.append(want_info)
                print(page_want_info)
            # 获取招聘详细信息
            if self.isdatail:
                for i in self.edge.s_eles('.el'):  # 获取招聘url
                    self.all_urls.append(i.attr('href'))
                random.shuffle(self.all_urls)
                for url in self.all_urls:  # 获取招聘信息
                    yield scrapy.Request(url=url, callback=self.parse)
                    try:
                        job_name = self.edge.s_ele('xpath:/html/body/div[2]/div[2]/div[2]/div/div[1]/h1').text  # 招聘职位
                        compensation = self.edge.s_ele(
                            'xpath:/html/body/div[2]/div[2]/div[2]/div/div[1]/strong').text  # 招聘薪资
                        required_info = self.edge.s_ele('.msg ltype').text  # 招聘要求
                        address = self.edge.s_ele('xpath:/html/body/div[2]/div[2]/div[3]/div[2]/div/p').text  # 上班地址
                        company_info = self.edge.s_ele('.tmsg inbox').text  # 公司信息
                        print(job_name, address, compensation)
                    except ElementNotFoundError:
                        pass
                self.edge.get(self.start_urls[0])
                self.all_urls = []

    def start_requests(self):
        yield scrapy.Request(
            url=self.start_urls[0],
            callback=self.get_all_want_info
        )

    def parse(self, response, **kwargs):
        pass


from scrapy import cmdline

cmdline.execute("scrapy crawl _51job".split())
都 “3202”年了还用 selemunim ?教你使用 scrapy + DrissionPage 爬取51job 和 过滑块验证码_第2张图片 搜索链接

如果想要分条件搜索,直接控制浏览器点击即可,此处不在赘述 


总结

本文使用 scrapy + DrissionPage 爬取 51job 招聘信息,因为DrissionPage 打开的是原有的浏览器驱动,无需下载其他驱动并且能任何自动化特征值,遇到51job滑块验证码的通过率几乎在100%。爬取速度也不错,是个强大又简单的工具。

你可能感兴趣的:(网站爬虫,scrapy)