前言
在爬取网站数据,往往会碰到一些加密的数据或者各种各样的验证码,可是 直接使用 request 需要js 逆向耗费大量时间,但使用 selemunim 等自动化工具又很容易被识别。哪有没有一种折中的办法既可以有request 请求的速度又有selemunim 的简单的操作?或许DrissionPage 可以帮助你
概述:DrissionPage 是一个基于 python 的网页自动化工具。它既能控制浏览器,也能收发数据包,还能把两者合而为一。可兼顾浏览器自动化的便利性和 requests 的高效率。它功能强大,内置无数人性化设计和便捷功能。它的语法简洁而优雅,代码量少,对新手友好。
本库采用全自研的内核,内置了 N 多实用功能,对常用功能作了整合和优化,对比 selenium,有以下优点:
open
状态的 shadow-root更多用法和概述不在此在说明,详细用法点击这里
准备工具:
pycharm 3.7
scrapy 2.9.0
DrissionPage 3.2.30
在pycharm 终端依次输入:
scrapy startproject _51job
cd _51job
scrapy genspider a_51job www.51job.com
创建好的文件如下:
因为 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
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())
如果想要分条件搜索,直接控制浏览器点击即可,此处不在赘述
本文使用 scrapy + DrissionPage 爬取 51job 招聘信息,因为DrissionPage 打开的是原有的浏览器驱动,无需下载其他驱动并且能任何自动化特征值,遇到51job滑块验证码的通过率几乎在100%。爬取速度也不错,是个强大又简单的工具。