2024年爬取BOSS直聘的操作

SCrapy框架实现对BOSS直聘的爬取

文章目录

  • SCrapy框架实现对BOSS直聘的爬取
    • 对SCrapy框架的一个简单认识
      • Scrapy 组件的作用
      • Scrapy 数据流
    • 1. 测试反爬
    • 2. 定义一个下载中间件类,截取spiders的请求(中间件直接截取请求,并且返回给Spider进行数据解析)
    • 数据解析操作

对SCrapy框架的一个简单认识

在这里插入图片描述

Scrapy 组件的作用

  1. Engine(引擎):负责控制系统所有组件之间的数据流,并在发生某些操作时触发事件。它是整个爬虫的核心。

  2. Scheduler(调度器):接收引擎的请求,对请求去重并放入队列中。当引擎请求新的请求时,将队列中的请求按顺序返回给引擎。

  3. Downloader(下载器):负责获取网页数据并将其返回给引擎,引擎再将数据传给 Spiders(爬虫)。

  4. Spiders(爬虫):解析响应,从中提取出 Items(项目)和新的 Requests(请求)。

  5. Item Pipeline(项目管道):处理爬虫提取的项目,包括清理、验证和存储项目。

  6. Downloader middlewares(下载器中间件):处理从引擎到下载器的请求和从下载器到引擎的响应,用于在这些过程中修改或替换请求和响应。

  7. Spider middlewares(爬虫中间件):处理爬虫的输入(响应)和输出(项目和请求),可以对这些数据进行修改、添加或删除。

Scrapy 数据流

  1. 初始请求

    • Scrapy 会实例化一个 Crawler 对象,在该对象中创建 Spider 对象和 Engine 对象。
    • 通过 Engine 对象打开 Spider,并生成第一个 request(请求)。
  2. 请求处理流程

    • 步骤 1:Engine 从 Spiders 获取初始请求。
    • 步骤 2:Engine 把请求给调度器,并询问下一次请求。
    • 步骤 3:Scheduler 对 URL 去重,放到队列中等待,并把下一个 request 返回给 Engine。
    • 步骤 4:Engine 把从调度器返回的 request 经过下载中间件交给下载器。
    • 步骤 5:Downloader 下载页面后生成一个 Response(响应),并通过下载器中间件将其发送到 Engine。
    • 步骤 6:Engine 接收响应,并通过爬虫中间件将其发送到爬虫进行处理。
    • 步骤 7:爬虫接收到响应,解析处理响应,提取出 Items 和 新的 Requests,再通过爬虫中间件提交给 Engine。
    • 步骤 8:Engine 把接收到的 Items 提交给 Item Pipeline,把接收到的 Requests 提交给调度器。
  3. 重复过程

    • 重复上述步骤,直到 Scheduler 中没有请求为止。

拿到一个网站爬取需求首先需要进行分析网站的反爬措施,再根据反爬漏洞想到对应的解决方法

1. 测试反爬

import time
from random import randint, choice
import requests

url = 'https://ja.58.com/job.shtml?utm_source=sem-baidu-pc&spm=u-2few7p4vh988mb62t1.2few8w827wgt4eurg.kd_201345177084.cr_43861026238.ac_20304970.cd_11302497077865040299'

user_agents = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.0.0',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36 Edg/100.0.0.0'
]

headers = {
    'User-Agent': choice(user_agents)
}

response = requests.get(url=url, headers=headers)

with open('test.html', 'w', encoding='utf-8') as f:
    f.write(response.text)

# 随机延时 1 到 5 秒
time.sleep(randint(1, 5))

在这里插入图片描述

可知直接爬取会被屏蔽,但是正常打开没有问题

在这里插入图片描述

因此想到用来selenium库来进行打开操作同时获取cookie保存

 def getcookie(self, url, cookies):
        driver = webdriver.Chrome()
        driver.get(url)
        time.sleep(6)
        dict_cookies = driver.get_cookies()
        json_cookies = json.dumps(dict_cookies)
        with open(cookies, "w") as fp:
            fp.write(json_cookies)
            print('Cookies保存成功!')
        driver.quit()
def load_cookies(self):
        with open(self.cookie_file, "r") as fp:
            cookies = json.load(fp)
        for cookie in cookies:
            if 'domain' in cookie:
                del cookie['domain']
            self.driver.add_cookie(cookie)

2. 定义一个下载中间件类,截取spiders的请求(中间件直接截取请求,并且返回给Spider进行数据解析)

class SeleniumMiddleware:
    query = ""
    city_id = ""

    def __init__(self):
        self.cookie_file = 'boss_cookies.json'
        # 检查文件是否存在,如果不存在则创建一个空文件
        if not os.path.exists(self.cookie_file):
            with open(self.cookie_file, 'w') as f:
                pass
        self.getcookie('https://www.zhipin.com/web/geek/job-recommend', self.cookie_file)
        self.driver = webdriver.Chrome()

    def getcookie(self, url, cookies):
		#此处省略
    def load_cookies(self):
		#此处省略

    def process_request(self, request, spider):
        try:
            if request.meta.get('first_request', True):
                qe = input('请搜索岗位和城市id(空格隔开):').split(' ')
                self.query = qe[0]
                self.city_id = qe[1]
                target_url = f"https://www.zhipin.com/web/geek/job?query={self.query}&city={self.city_id}&page=1"
                q: str = self.query
                c = self.city_id
                request.meta['first_request'] = False
            else:
                page = int(request.meta.get('page_number'))
                target_url = f"https://www.zhipin.com/web/geek/job?query={self.query}&city={self.city_id}&page={page}"
            print(f"Fetching URL: {target_url}")
            self.driver.get(target_url)
            self.load_cookies()
            self.driver.refresh()

            WebDriverWait(self.driver, 20).until(
                EC.presence_of_element_located((By.CLASS_NAME, "job-card-wrapper"))
            )

            data = self.driver.page_source
            return HtmlResponse(url=request.url, body=data, encoding='utf-8', request=request)
        except Exception as e:
            print(f"An error occurred: {e}")
            return HtmlResponse(url=request.url, status=500, request=request)

    def __del__(self):
        if self.driver:
            self.driver.quit()

请求代码

  WebDriverWait(self.driver, 20).until(
                EC.presence_of_element_located((By.CLASS_NAME, "job-card-wrapper"))
            )

因为boss直聘具有反爬操作,很多时候能够检测出来不是正常用户,需要用该方法反复进行请求操作直到html页面中能够获取我们想要的标签内容(这个标签下的很多数据都是我们需要进行爬取操作的数据)

数据解析操作

使用Xpath来进行,同时对空数据进行处理

import scrapy
from ..items import BossItem


class BossSpider(scrapy.Spider):
    name = "boss"
    allowed_domains = ["www.zhipin.com"]
    start_urls = ["https://www.zhipin.com/"]
    page = 1

    def parse(self, response):
        with open('test.html', 'w', encoding='utf-8') as f:
            f.write(response.text)

        # 改进的XPath表达式
        li_list = response.xpath('//li[@class="job-card-wrapper"]')
        print(f"Number of items found: {len(li_list)}===============================================")

        for li in li_list:
            title = li.xpath(".//span[@class='job-name']/text()").extract_first() or ''
            salary = li.xpath(".//span[@class='salary']/text()").extract_first() or ''
            area = li.xpath(".//span[@class='job-area']/text()").extract_first() or ''

            # 确保提取job_lable_list的正确性
            job_lable_list = li.xpath(".//ul[@class='tag-list']//text()").extract()
            if len(job_lable_list) >= 2:
                experience = job_lable_list[0] or ''
                education = job_lable_list[1] or ''
            else:
                experience = ''
                education = ''

            company = li.xpath(".//h3[@class='company-name']/a/text()").extract_first() or ''

            # 确保提取company_message的正确性
            company_message = li.xpath(".//ul[@class='company-tag-list']//text()").extract()
            company_type = company_message[0] if company_message else ''

            # 提取boon字段
            boon = li.xpath('.//div[@class="job_card_footer"]//div[@class="info-desc"]/text()').extract()
            boon = boon[0] if boon else None
            # 技能
            skill_list = li.xpath(
                ".//div[@class='job-card-footer clearfix']//ul[@class='tag-list']/li/text()").extract() or []
            skill = "|".join(skill_list)
            # 创建BossItem对象并传递数据
            book = BossItem(
                title=title,
                address=area,
                salary=salary,
                experience=experience,
                education=education,
                company=company,
                companyType=company_type,
                skill_list=skill,
            )
            yield book

        if self.page < 10:
            self.page += 1
            next_url = f"https://www.zhipin.com/web/geek/job?query=java&city=101210100&page={self.page}"
            yield scrapy.Request(
                url=next_url,
                callback=self.parse,
                meta={'page_number': self.page, 'first_request': False}
            )

spider/boss.py中代码的注意事项

        if self.page < 10:
            self.page += 1
            next_url = f"https://www.zhipin.com/web/geek/job?query=java&city=101210100&page={self.page}"
            yield scrapy.Request(
                url=next_url,
                callback=self.parse,
                meta={'page_number': self.page, 'first_request': False}
            )

注意:此代码next_url传过去不会真正的被下载器中间件处理,而是为了防止不报错而进行的(不知道哪错了)

中间件部分代码

 if request.meta.get('first_request', True):
                qe = input('请搜索岗位和城市id(空格隔开):').split(' ')
                self.query = qe[0]
                self.city_id = qe[1]
                target_url = f"https://www.zhipin.com/web/geek/job?query={self.query}&city={self.city_id}&page=1"
                q: str = self.query
                c = self.city_id
                request.meta['first_request'] = False
            else:
                page = int(request.meta.get('page_number'))
                target_url = f"https://www.zhipin.com/web/geek/job?query={self.query}&city={self.city_id}&page={page}"

由于csdn下载代码需要开启vip具体代码实现可以访问我的github:

2240774934/Crawler_instances: 最新BOSS直聘爬取以及其他常见网站爬取 (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/768042.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

动态住宅代理IP的优势是什么?什么地方用到?

在大数据时代的背景下&#xff0c;代理IP成为了很多企业顺利开展的重要工具。代理IP地址可以分为住宅代理IP地址和数据中心代理IP地址。选择住宅代理IP的好处是可以实现真正的高匿名性&#xff0c;而使用数据中心代理IP可能会暴露自己使用代理的情况。 住宅代理IP是指互联网服务…

Android存储权限梳理及api接口调用

Android存储权限梳理及api接口调用 背景 Android开发中需要了解android 存储权限管理和对应的api使用逻辑。 概述 Android系统的文件存储按存储介质类型分为内部存储和外部存储&#xff0c;按存储目录类型分为私有目录和公共目录&#xff1b;对于Android系统中的进程来说&a…

【力扣 - 每日一题】3099. 哈沙德数 | 模拟 (Go/C++)

题目内容 如果一个整数能够被其各个数位上的数字之和整除&#xff0c;则称之为 哈沙德数&#xff08;Harshad number&#xff09;。给你一个整数 x 。如果 x 是 哈沙德数 &#xff0c;则返回 x 各个数位上的数字之和&#xff0c;否则&#xff0c;返回 -1 。 示例 1&#xff1…

修改CentOS7 yum源

修改CentOS默认yum源为阿里镜像源 备份系统自带yum源配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 下载ailiyun的yum源配置文件 CentOS7 yum源如下&#xff1a; wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun…

按是否手工执行测试的角度划分:手工测试、自动化测试

1.手工测试&#xff08;Manual testing&#xff09; 手工测试是由人一个一个的输入用例&#xff0c;然后观察结果&#xff0c;和机器测试相对应&#xff0c;属于比较原始但是必须的一个步骤。 由专门的测试人员从用户视角来验证软件是否满足设计要求的行为。 更适用针对深度…

如何批量创建、提取和重命名文件夹!!!

你是否还在一个一个手动创建文件名&#xff01; 你是否还在一个一个手动提取文件名&#xff01; 你是否还在一个一个手动修改文件名&#xff01; 请随小生一起批量自动创建、提取、重命名&#xff01; 1、批量创建文件夹 【案例】创建1日-31日共31个文件夹 【第一步】在A列…

Atom CMS v2.0 SQL 注入漏洞(CVE-2022-25488)

前言 CVE-2022-25488 是一个发现于 Telesquare SDT-CW3B1 设备中的命令注入漏洞。这一漏洞可以被未经认证的远程攻击者利用&#xff0c;通过特殊构造的 HTTP 请求在设备上执行任意命令。以下是关于该漏洞的详细信息&#xff1a; 漏洞详细信息 漏洞编号: CVE-2022-25488影响范…

统一开放平台实现方案(访微信SDK)

需求分析 在互联中&#xff0c;我们的服务是不对外开放的&#xff0c;但是有先场景下我们可以对外开放&#xff0c;但是必须是系统所允许的用户才可以&#xff0c;这样做一方面保证安全&#xff0c;另一方面可以提升平台的能力&#xff0c;比如调用微信的接口必须要进行微信开…

统计信号处理基础 习题解答11-11

题目 考虑矢量MAP估计量 证明这个估计量对于代价函数 使贝叶斯风险最小。其中&#xff1a;, &#xff0c;且. 解答 贝叶斯风险函数&#xff1a; 基于概率密度的非负特性&#xff0c;上述对积分要求最小&#xff0c;那就需要内层积分达到最小。令内层积分为&#xff1a; 上述积…

为什么网上商店需要翻译成其他语言

网上商店不仅仅是一个可以买到商品的网站。它是一个完整的电子商务平台&#xff0c;为来自世界各地的用户提供购买所需物品的机会。但是&#xff0c;为了让这些用户舒适地使用网站&#xff0c;需要高质量的翻译和本地化。 本地化是指产品或服务适应特定文化或市场的过程。它包…

匠心独运:红酒与手工艺的很好结合

在岁月的长河中&#xff0c;红酒与手工艺都以其不同的魅力和技艺&#xff0c;书写着各自的故事。当这两者相遇&#xff0c;仿佛是一场跨越时空的对话&#xff0c;不仅展现了匠心独运的技艺之美&#xff0c;更在无声中诉说着对品质与生活的热爱。今天&#xff0c;就让我们一起探…

「算法题」二分查找算法演示

一个样式更加美观大方的HTML页面示例,其中包括了二分查找算法的演示。 布局描述 页面主体使用白色背景,加上轻微的阴影和圆角边框,使页面看起来更加精致。输入框和按钮使用了更加现代的样式,包括圆角边框和悬浮效果。按钮使用了鲜明的颜色,以吸引用户点击。搜索结果显示时…

html+js+css登录注册界面

拥有向服务器发送登录或注册数据并接收返回数据的功能 点赞关注 界面 源代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>Login and Registration Form</title> <style> * …

linux命令行操作

一、看二进制文件 od -t x1 1.txt | less 二、看信号 kill -l man 7 signal 三、查看当前进程的pid号 echo $$

44.实现管理HOOK点的链表对象

上一个内容&#xff1a;43.实现HOOK接管寄存器数据 以 43.实现HOOK接管寄存器数据 它的代码为基础进行修改 首先创建一个类 这里创建的名为HOOKPOINT.h HOOKPOINT.cpp文件里面的内容 #include "pch.h" #include "HOOKPOINT.h"HOOKPOINT::HOOKPOINT() {…

钉钉机器人接入Dify工作流

实现钉钉机器人接入dify工作流&#xff0c;完成ai 流式问答 代码地址 有用的话点个star github地址 效果 配置使用 修改.env_template文件 为.env 设置.env文件内的环境变量 API_KEY: dify的api_keyAPI_URL: dify 的api接口CLIENT_ID : 钉钉机器人应用的idCLIENT_SECRET:钉…

Arthas实战(1)- 运行Arthas

1. 下载Arthas 下载到服务器&#xff1a; wget https://github.com/alibaba/arthas/releases/download/arthas-all-3.7.1/arthas-bin.zip解压 Arthas unzip arthas-bin.zip -d arthas删除压缩包 rm -f arthas-bin.zip 2. 启动Arthas 运行 Arthas java -jar arthas/arthas-bo…

高编:共享内存(key)

system v &#xff1a; 共享内存 信号量集 IPC对象操作通用框架&#xff1a; 0x ftok key值 > 申请 》读写 》关闭 》卸载 优点&#xff1a; 共享内存效率高没有读写阻塞 操作流程&#xff1a; key 》申请对象 》映射对象》读写对象》撤销映射 》删除对象…

Django 一对一关系

作用&#xff1a; 两个数据库表建立外键关系当外键表的数据被删除时&#xff0c;主表的数据也会一并删除。 1&#xff0c;添加表模型 Test/app8/views.pyfrom django.db import modelsclass User(models.Model):username models.CharField(max_length50, uniqueTrue)email …

Webpack: Dependency Graph 管理模块间依赖

概述 Dependency Graph 概念来自官网 Dependency Graph | webpack 一文&#xff0c;原文解释&#xff1a; Any time one file depends on another, webpack treats this as a dependency. This allows webpack to take non-code assets, such as images or web fonts, and als…