爬虫进阶-反爬破解8(反爬的实战练习:爬虫文件的解析和数据的抓取+反爬措施的分析和突破+Scrapy接入Cookie池管理系统+分布式爬虫的架设)

news2024/12/27 18:43:25

目录

一、爬虫文件的解析和数据的抓取

(一)项目的知识点

(二)实践操作:新建项目抓取数据

(三)总结

二、反爬措施的分析和突破

(一)项目知识点补充

(二)实践操作:Scrapy破解数据加密操作

(三)总结

三、Scrapy接入Cookie池管理系统

(一)项目知识点补充

(二)环境介绍

(三)实践操作:Scrapy+Cookie池管理系统

(四)总结

四、分布式爬虫的架设

(一)项目知识点补充

(二)环境介绍

(三)实践操作:打造分布式爬虫框架

(四)总结


一、爬虫文件的解析和数据的抓取

(一)项目的知识点

(1)Scrapy项目和爬虫文件

(2)分析目标站和抓取数据

(3)数据存储到本地文件中

(二)实践操作:新建项目抓取数据

1.安装scrapy:pip install scrapy

2.创建项目:scrapy startproject shanzhi

3.爬虫初始文件:scrapy genspider sz http://shanzhi.spbeen.com

4.在sz.py中修改代码:

import scrapy

class SzSpider(scrapy.Spider):
    name = 'sz'
    allowed_donains = ['shanzi.spbeen.com']
    # start_urls = ['http://shanzhi.spbeen.com/']
    basic_url = 'http://shanzhi.spbeen.com/api/search/?word=&page={}&_=1631533868181'

    def start_requests(self):
        for i in range(1,17): //1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
            url = self.basic_url.format(i)
            yield scrapy.Request(url, callback=self.parse, meta={'number':i})

    def parse(self,response):
        # print(response, response.mata)
        number = response.meta.get('number', False)
        divcard = response.xpath(".//div[contains(@class,'animate__animated')]")
        for div in divcard:
            item = {}
            item['链接'] = div.xpath('./div/h5/a/@href').extract_first()
            item['岗位'] = div.xpath('./div/h5/a/text()').extract_first()
            item['薪资'] = div.xpath('./div/h5/small/text()').extract_first()
            item['公司'] = div.xpath('./div/p[last()]/small[1]/text()').extract_first()
            # print(item)
            yield item

        if number and len(divcard) == 10:
            number += 16
            url = self.basic_url.format(number)
            yield scrapy.Request(url, callback=self.parse, meta={'number':number})

5.新建python文件:run.py

from scrapy.cmdline import execute
execute("scrapy crawl sz".split())

6.在settings.py中的遵循ROBOTS协议中修改为ROBOTSTXT_OBEY=False,

DEFAULT_REQUESTS_HEADERS注释掉的内容打开并添加user_agent内容

7.在settings.py中的ITEM_PIPLINES注释掉的内容打开,表示可以存储数据

8.修改piplines.py中的代码

import csv
import datetime 

class ShanzhiPipeline(object):
    def __init__(self):
        date = datetime.datetime.now()
        date_str = date.strftime("%Y-%m-%d-%H-%M")
        self.file = open("{}_date.csv".format(date_str),'a+')
        self.writer = csv.writer(self.file)
        self.writer.writerow(['链接','岗位','薪资','公司'])

    def process_item(self, item, spider):
        self.writer.writerow([v for k,v in item.items()])
        return item  

(三)总结

(1)了解Scrapy项目各部分组件的功能

(2)熟悉爬虫文件和管道文件,各司其职

(3)准备数据解密和Cookie的接入

二、反爬措施的分析和突破

(一)项目知识点补充

1.下载器中间件作用

2.Scrapy的Response响应特性

3.Scrapy项目的运行流程

(二)实践操作:Scrapy破解数据加密操作

1.将font.ttf文件导入

2.在middewares.py文件中修改代码内容

from scrapy import signals
from fontTools.ttLib import TTFont


# class ShanzhiSpiderMiddleware(object):这段不需要修改

class ShanzhiDownloadMiddleware(object):
    # 只书写需要修改的部分
    def from_crawler(cls, crawler):
        s = cls()
        font = TTFont("font.ttf")
        result_dict = {}
        for k,v in font['cmap'].getBestCmap().items():
            # hex()函数是将十进制转成16进制
            k = hex(k).replace('0x','&#x')+';'
            v = int(v[8:10])-1
            result_dict[k]=str(v)

        crawler.signals.connect(s.spider_opened,signal=signals.spider_opened)
        return s

    def process_response(self,request,response,spider):
        #response的网页部分,不能修改,只能替换全部网页
        #取出response的网页部分,修改网页内容,再将网页内容替换到response上,得到新的new_response
        html = response.text
        for k,v in result_dict.items():
            html = html.replace(k,v)
        new_reponse = response.replace(body=html)
        return new_response

3.将settings.py文件中的DOWNLODER_MIDDLEWARES注释内容打开

(三)总结

(1)下载器中间件负责请求输出和响应

(2)signal信号道是scrapy的重载机制

(3)response的网页内容不可直接修改

三、Scrapy接入Cookie池管理系统

(一)项目知识点补充

(1)下载器中间件的请求头处理函数

(2)Cookie的维护和提取函数

(3)Scrapy中请求头的设置

(二)环境介绍

(1)爬虫项目

(2)Cookie池管理系统

(3)Redis数据库

(三)实践操作:Scrapy+Cookie池管理系统

1.修改sz.py文件中的代码内容

import scrapy

class SzSpider(scrapy.Spider):
    name = 'sz'
    allowed_donains = ['shanzi.spbeen.com']
    # start_urls = ['http://shanzhi.spbeen.com/']
    basic_url = 'http://shanzhi.spbeen.com/api/search/?word=&page={}&_=1631533868181'

    def start_requests(self):
        for i in range(1,17): //1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
            url = self.basic_url.format(i)
            yield scrapy.Request(url, callback=self.parse, meta={'number':i})

    def parse(self,response):
        # print(response, response.mata)
        number = response.meta.get('number', False)
        divcard = response.xpath(".//div[contains(@class,'animate__animated')]")
        for div in divcard:
            item = {}
            item['链接'] = div.xpath('./div/h5/a/@href').extract_first()
            item['岗位'] = div.xpath('./div/h5/a/text()').extract_first()
            item['薪资'] = div.xpath('./div/h5/small/text()').extract_first()
            item['公司'] = div.xpath('./div/p[last()]/small[1]/text()').extract_first()
            # print(item)
            #yield item
            yield scrapy.Request(item['链接'],callback=self.parse_detail, meta={'item':item})

        if number and len(divcard) == 10:
            number += 16
            url = self.basic_url.format(number)
            yield scrapy.Request(url, callback=self.parse, meta={'number':number})
    def parse_detail(self, response):
        item = response.meta.get('item',{})
        item['编号'] = response.xpath('.//h4[@class="display-5"]/text()').extract_first()
        item['编号'] = item['编号'].split(']')[0].split(':')[-1]
        item['薪资'] = response.xpath('.//h4[@class="display-5"]/span/text()').extract_first()
        item['经验'] = response.xpath('.//p[@class="lead"]/span[1]/text()').extract_first()
        item['公司地址'] = response.xpath('.//div[@class="col-4"]//text()').extract()
        item['公司地址'] = "".join([address for address in item['公司地址'] if "地址:" in address]).replace(" ","").replace("\n","")
        item['福利待遇工作职责描述'] = "".join(response.xpath('.//div[@class="col-8"]//text()').extract())
        item['招聘人数'] = response.xpath('.//p[@class="lead"]/span[last()]/text()').extract_first()
        item['简历邮箱'] = response.xpath('.//div[@class="jumbotron bg-white"]/p[last()]/span[2]/text()').extract_first()
        yield item

2.在settings.py文件中的DEFAULT_REQUEST_HEADERS中添加cookie,COOKIES_ENABLED=False注释内容打开

3.在middlewares.py中修改代码内容

import requests
import json

# 只显示修改部分内容
def process_request(self, request, spider):
    url = 'http://127.0.0.1:8000/api/extract_cookie/?website=shanzhi&number=1'
    response = requests.get(url)
    cookie_dict = json.loads(response.text)
    request.cookies = cookie_dict['cookie']
    # return None

4.若用middlewares.py设置了cookie,需要将2中的settings.py文件中的DEFAULT_REQUEST_HEADERS中的cookie和COOKIES_ENABLED=False打开的内容注释掉(还原回去)

(四)总结

(1)注意账号的活性,尽量多的使用账号

(2)Cookie的设置有多种方法,挑选适合爬虫的方法

(3)注意Cookie池环境的搭建

四、分布式爬虫的架设

(一)项目知识点补充

1.Redis的任务存储

2.爬虫分为任务爬虫和工作者爬虫

3.数据存储改成Mongo

(二)环境介绍

1.爬虫项目

2.Cookie池管理系统

3.Redis数据库和Mongo数据库

(三)实践操作:打造分布式爬虫框架

1.在终端窗口输入命令:pip install gerapy scrapyd

2.新建两个终端,其中一个终端输入命令:

(1)cd Desktop

(2)mkdir scrapyd_dir

(3)cd scrapyd_dir

(4)scrapyd

另一个终端输入命令:

(1)cd Desktop

(2)gerapy init

(3)cd gerapy

(4)gerapy migrate

(5)gerapy runserver 0.0.0.0:8001

3.删除font.ttf文件,修改middlewares.py文件代码内容

import io  

class ShanzhiDownloadMiddleware(object):
    # 只显示修改内容
    def from_crawler(cls, crawler):
        s = cls()
        # 将本地硬盘上的文件换成在线文件
        fonturl = 'http://shanzhi.spbeen.com/static/fonts/szec.ttf'
        fontresp = requests.get(fonturl)
        font = TTFont(io.BytesIO(fontresp.content))
        result_dict = {}
        for k,v in font['cmap'].getBestCmap().items():
            # hex()函数是将十进制转成16进制
            k = hex(k).replace('0x','&#x')+';'
            v = int(v[8:10])-1
            result_dict[k]=str(v)

        crawler.signals.connect(s.spider_opened,signal=signals.spider_opened)
        return s

4.修改piplines.py文件代码内容

import csv
import datetime 
import pymongo

class ShanzhiPipeline(object):
    def __init__(self):
        self.client = pymongo.MongoClient(host='192.168.2.38', port=27017)
        self.db = self.client['shanzhi']
        self.collect = self.db['sz']

    def process_item(self, item, spider):
        self.collect.insert(item)
        return item  

5.复制sz.py分别为sz-1.py和sz-2.py,并对两个文件进行改造

sz-1.py代码如下:需要将settings.py中的ITEM_PIPLINES注释掉(还原)

import scrapy

class SzSpider(scrapy.Spider):
    name = 'sz1'
    allowed_donains = ['shanzi.spbeen.com']
    # start_urls = ['http://shanzhi.spbeen.com/']
    basic_url = 'http://shanzhi.spbeen.com/api/search/?word=&page={}&_=1631533868181'
    custom_settings = {
        'ITEM_PIPELINES' : {'shanzhi.pipelines.RedisPipeline':300,}
    }

    def start_requests(self):
        for i in range(1,17): //1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
            url = self.basic_url.format(i)
            yield scrapy.Request(url, callback=self.parse, meta={'number':i})

    def parse(self,response):
        # print(response, response.mata)
        number = response.meta.get('number', False)
        divcard = response.xpath(".//div[contains(@class,'animate__animated')]")
        for div in divcard:
            item = {}
            item['链接'] = div.xpath('./div/h5/a/@href').extract_first()
            item['岗位'] = div.xpath('./div/h5/a/text()').extract_first()
            item['薪资'] = div.xpath('./div/h5/small/text()').extract_first()
            item['公司'] = div.xpath('./div/p[last()]/small[1]/text()').extract_first()
            # print(item)
            yield item

        if number and len(divcard) == 10:
            number += 16
            url = self.basic_url.format(number)
            yield scrapy.Request(url, callback=self.parse, meta={'number':number})

修改添加piplines.py文件内容,添加class,代码如下:

import pymongo
import redis
import json

class RedisPipeline(object):
    def __init__(self):
        self.redis = redis.StrictRedis(host='192.168.2.38', port=6666, db=0)

    def process_item(self, item, spider):
        self.redis.rpush('sz:item',json.dumps(item))
        return item  

class ShanzhiPipeline(object):
    def __init__(self):
        self.client = pymongo.MongoClient(host='192.168.2.38', port=27017)
        self.db = self.client['shanzhi']
        self.collect = self.db['sz']

    def process_item(self, item, spider):
        self.collect.insert(item)
        return item  

新建run-sz1.py和run-sz2.py,代码如下类比:

from scrapy.cmdline import execute
execute("scrapy crawl sz".split())

sz-2.py代码如下:

import scrapy
from scrapy_redis.spiders import RedisSpider
import json

class SzSpider(RedisSpider):
    name = 'sz2'
    allowed_donains = ['shanzi.spbeen.com']
    redis_key = 'sz:item'
    custom_settings = {
        'REDIS_HOST': '192.168.2.38',
        'REDIS_PORT': 6666,
        'SCHEDULER': 'scrapy_redis_scheduler.Scheduler',
        'DUPEFILTER_CLASS': 'scrapy_redis.dupefilter.RFPDupeFilter',
        'SCHEDULER_PERSIST': 'True',
        'SCHEDULER_QUEUE_CLASS': 'scrapy_redis.queue.PriorityQueue',
        'ITEM_PIPELINES': {'shanzhi.pipelines.ShanzhiPipeline':300,},
    }
    
    def make_request_from_data(self, data):
        item = json.loads(data)
        return self.make_requests_from_url(item['链接'], item)

    def make_requests_from_url(self, url, item):
        return scrapy.Request(url, dont_filter=True, meta={'item': item}, callback=self.parse_detail)
   
    def parse_detail(self, response):
        item = response.meta.get('item',{})
        item['编号'] = response.xpath('.//h4[@class="display-5"]/text()').extract_first()
        item['编号'] = item['编号'].split(']')[0].split(':')[-1]
        item['薪资'] = response.xpath('.//h4[@class="display-5"]/span/text()').extract_first()
        item['经验'] = response.xpath('.//p[@class="lead"]/span[1]/text()').extract_first()
        item['公司地址'] = response.xpath('.//div[@class="col-4"]//text()').extract()
        item['公司地址'] = "".join([address for address in item['公司地址'] if "地址:" in address]).replace(" ","").replace("\n","")
        item['福利待遇工作职责描述'] = "".join(response.xpath('.//div[@class="col-8"]//text()').extract())
        item['招聘人数'] = response.xpath('.//p[@class="lead"]/span[last()]/text()').extract_first()
        item['简历邮箱'] = response.xpath('.//div[@class="jumbotron bg-white"]/p[last()]/span[2]/text()').extract_first()
        yield item

可以在127.0.0.1:8001/#/project链接下进行管理部署

(四)总结

1.分布式爬虫,注意数据的存放位置,爬虫必须能读取到

2.Redis是任务临时存放的位置,可以放url或数据结构

3.分布式爬虫分任务发布和任务处理

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

binutils 2.40 Linker (ld) 官方文档下载

前言 最近需要熟悉 elf 与 共享库 的链接与加载流程,需要先了解 elf 文件 是怎么链接的,链接脚本如何阅读 最有效的方式是查看 GNU 官方的 Linker (ld) 文档,通过查找,这个 Linker (ld) 属于 GNU binutils,当前的较新…

JS DataTable中导出PDF中文乱码

JS DataTable中导出PDF中文乱码 文章目录 JS DataTable中导出PDF中文乱码一. 问题二. 原因三. vfs_fonts.js四. pdfmake.js五. 解决六.参考资料 一. 问题 二. 原因 DataTable使用pdfmake,pdfmake默认字体为Roboto,不支持中文字体。添加自己的字体&#…

Shopee本土店与跨境店有何区别?如何入驻?

截止到目前,虾皮全球覆盖的站点已经有11个,其中东南亚站点依然是消费力强劲的大站点,包括马来西亚、泰国、印度尼西亚、菲律宾、越南、新加坡。到了2023,仍然有非常大的市场空间。 东南亚人口密度大,还是全球网络发展…

【项目管理】项目中如何进行风险管理

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

threejs(4)-纹理材质高级操作

一、纹理重复_缩放_旋转_位移操作 // 导入threejs import * as THREE from "three"; // 导入轨道控制器 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; // 导入lil.gui import { GUI } from "three/examples/jsm/l…

基于5G网关的风力发电远程监测方案优势

风力发电是清洁能源的典型代表,是我国能源结构转型的重要组成。近年来我国大力发展风能、水能、光伏等清洁能源,加速双碳战略,长期致力于创造人与生态友好和谐的人居社会。 针对风力发电机组和厂区的运营和管理,5G技术、物联网技…

CrossOver23.6软件激活码怎么获取 CrossOver软件2023怎么激活

CrossOver一款类虚拟机,它的主要功能是在mac系统中安装windows应用程序。其工作原理是将exe格式的windows应用程序安装包安装至CrossOver容器中,并将运行该exe文件所需的配置文件下载至容器中,便能在mac正常运行windows应用程序了。下面就让我…

JavaSE介绍与第一个Java程序

JavaSE介绍与第一个Java程序 一、Java简介二、Java特点三、编译运行过程四、JDK、JRE和JVM的关系五、第一个Java程序1、HelloWorld2、注意事项 六、标识符与命名规范1、标识符(1)什么是标识符(2)标识符的命名规则 2、命名规范&…

C++初阶:C/C++内存管理

一.C/C内存分布 先来回顾一下C语言内存分区示意图如下: 代码区: 程序执行代码一般存放在代码区,字符串常量以及define定义的常量也可能存放在代码区。 常量区: 字符串,数字等常量以及const修饰的全局变量往往存放在…

【UE】UMG通信的三种方法

目录 前言 方法一:通过“获取类的所有控件”节点通信 方法二:当创建控件蓝图时传入其它控件蓝图的对象引用 *方法三:使用HUD类来管理UMG通信 前言 首先我们创建了三个控件蓝图,那么其中的一个控件蓝图如何与剩下的控件蓝图通…

网络编程进化史:Netty Channel 的崭新篇章

上篇文章(Netty 入门 — ByteBuf,Netty 数据传输的载体),我们了解了 Netty 的数据是以 ByteBuf 为单位进行传输的,但是有了数据,你没有通道,数据是无法传输的,所以今天我们来熟悉 Ne…

2023 年专业人士必须尝试的 15 款人工智能工具

在本文中,我们将看到一些人工智能驱动的工具,这些工具将在 2023 年彻底改变开发并使专业人士的生活变得轻松。我们将讨论旨在为专业人士提供支持的 15 种顶级人工智能和低代码工具。人工智能工具现在变得更加强大,使他们能够创造有影响力的产…

数字图像处理(十六)非局部均值去噪

文章目录 一、前言二、NL-means1.两个邻域块的相似度2.NL-means原理3.数学理论推导4.代码链接 参考链接 一、前言 在之前我们已经介绍过许多图像去噪的方法,比如均值滤波、中值滤波、高斯滤波等。今天我们要介绍一种新的去噪方法——非局部均值去噪(the…

如何构建一个外卖微信小程序

随着外卖行业的不断发展,越来越多的商家开始关注外卖微信小程序的开发。微信小程序具有使用方便、快速上线、用户覆盖广等优势,成为了商家们的首选。 那么,如何快速开发一个外卖微信小程序呢?下面就让我们来看看吧! 首…

二、W5100S/W5500+RP2040树莓派Pico<DHCP>

文章目录 1 前言2 简介2 .1 什么是DHCP?2.2 为什么要使用DHCP?2.3 DHCP工作原理2.4 DHCP应用场景 3 WIZnet以太网芯片4 DHCP网络设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 …

模型保存和加载

1、sklearn模型的保存和加载API from sklearn.externals import joblib 保存:joblib.dump(rf, ‘test.pkl’)加载:estimator joblib.load(‘test.pkl’) 2、决策树的模型保存加载案例 保存: import joblib from sklearn.model_selectio…

程序员想要网上接单却不知道如何是好?那这篇文章你可得收藏好了!

作为一名程序员,想要网上接单赚赚零花钱,提高生活水平,这当然是无可厚非的,甚至有许多人已经将网上接单作为主业。 可是面对网上五花八门的接单平台,看着网上真真假假的信息,你真的清楚如何选择吗&#xf…

CAP定理下:Zookeeper、Eureka、Nacos简单分析

CAP定理下:Zookeeper、Eureka、Nacos简单分析 CAP定理 C: 一致性(Consistency):写操作之后的读操作也需要读到之前的 A: 可用性(Availability):收到用户请求,服务器就必须给出响应 P…

整个自动驾驶小车001:概述

材料: 1,树梅派4b,作为主控,这个东西有linux系统,方便 2,HC-S104超声波模块,我有多个,不少于4个,我可以前后左右四个方向都搞一个 3,l298n模块,…

指定顺序输出

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…