scrapy初始第三波——CrawlSpider爬取拉勾招聘网

一,前言

  之前利用scrapy爬取伯乐在线,知乎时是用到scrapy的basic模板,即Spider,这次用CrawlSpider来爬取拉勾网的招聘信息

  CrawlSpider基于Spider,但是可以说是为全站爬取而生,是目前最流行的scrapy模板


二,创建工程

在cmd中cd进入项目的目录,然后输入:scrapy gensipder -t crawl lagou  www.lagou.com

默认生成:


三,简要说明

CrawlSpider是爬取那些具有一定规则网站的常用的爬虫,它基于Spider并有一些独特属性,也就是之前spider的爬取规则现在也适用,下面的参数可以按ctrl点击CrawlSpider获取源码

 

  • rules: 是Rule对象的集合,用于匹配目标网站并排除干扰
  • parse_start_url: 用于爬取起始响应,必须要返回ItemRequest中的一个。

因为rulesRule对象的集合,所以这里也要介绍一下Rule对象

它有几个参数:linkExtractorcallback=Nonecb_kwargs=Nonefollow=Noneprocess_links=Noneprocess_request=None

  • callback为回调函数,传入一个str,即回调函数的名字
  • follow为boolean类型,为true就继续跟踪,为false则不往下跟踪

其中的linkExtractor既可以自己定义,也可以使用已有LinkExtractor类,主要参数为:

  • allow:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。
  • deny:与这个正则表达式(或正则表达式列表)不匹配的URL一定不提取。
  • allow_domains:会被提取的链接的domains。
  • deny_domains:一定不会被提取链接的domains。
  • restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。还有一个类似的restrict_cs
四,拉勾招聘网招聘信息的爬取

4.1  rule的编写

输入拉勾网首页:https://www.lagou.com/

观察职位的url:https://www.lagou.com/jobs/3157876.html   为https://www.lagou.com/jobs/\d+.html  格式

此外我们在进入职位url之前必须从 https://www.lagou.com/zhaopin/Android/  ,https://www.lagou.com/gongsi/j118082.html之类的url进入,所以匹配https://www.lagou.com/zhaopin/*    https://www.lagou.com/gongsi/j\d+

4.2 parse_item的编写

这里不详细分析了,在如图一个个用css,或者xpath分析

具体代码如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ArticleSpider.items import FirstItemLoader, LagouJobItem

class LagouSpider(CrawlSpider):
    name = 'lagou'
    allowed_domains = ['www.lagou.com']
    start_urls = ['https://www.lagou.com/zhaopin/Python/']

    rules = (
        Rule(LinkExtractor(allow=("zhaopin/.*",)),follow=True),
        Rule(LinkExtractor(allow=("gongsi/j\d+.html",)), follow=True),
        Rule(LinkExtractor(allow=r'jobs/\d+.html'), callback='parse_job', follow=True),
    )


    def parse_job(self, response):
        #解析拉勾网的职位
        # pass
        # #i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()
        # #i['name'] = response.xpath('//div[@id="name"]').extract()
        # #i['description'] = response.xpath('//div[@id="description"]').extract()
        item_loader = FirstItemLoader(item=LagouJobItem(),response=response)
        item_loader.add_css("title", ".job-name::attr(title)")
        item_loader.add_value("url", response.url)

        item_loader.add_css("salary", ".job_request .salary::text")
        item_loader.add_xpath("job_city", "//*[@class='job_request']/p/span[2]/text()")
        item_loader.add_xpath("work_years", "//*[@class='job_request']/p/span[3]/text()")
        item_loader.add_xpath("degree_need", "//*[@class='job_request']/p/span[4]/text()")
        item_loader.add_xpath("job_type", "//*[@class='job_request']/p/span[5]/text()")

        item_loader.add_css("tags", '.position-label li::text')
        item_loader.add_css("publish_time", ".publish_time::text")
        item_loader.add_css("job_advantage", ".job-advantage p::text")
        item_loader.add_css("job_desc", ".job_bt div")
        item_loader.add_css("job_addr", ".work_addr")
        item_loader.add_css("company_name", "#job_company dt a img::attr(alt)")
        item_loader.add_css("company_url", "#job_company dt a::attr(href)")
        # item_loader.add_value("crawl_time", datetime.now())

        job_item = item_loader.load_item()
        # print(job_item)
        yield job_item
        pass

其中items代码如下:

import re
import scrapy
from scrapy.loader.processors import  TakeFirst,MapCompose,Join
from scrapy.loader import ItemLoade

class FirstItemLoader(ItemLoader):
    #自定义itemloader,继承scrapy的ItemLoader类
    default_output_processor = TakeFirst()

def remove_splash(value):
    #去掉工作城市的斜线
    return value.replace("/","")

class LagouJobItem(scrapy.Item):
    #拉勾网职位信息
    title = scrapy.Field()
    url = scrapy.Field()
    url_object_id = scrapy.Field()
    salary = scrapy.Field()
    job_city = scrapy.Field(
        input_processor=MapCompose(remove_splash),
    )
    work_years = scrapy.Field(
        input_processor = MapCompose(remove_splash),
    )
    degree_need = scrapy.Field(
        input_processor = MapCompose(remove_splash),
    )
    job_type = scrapy.Field()
    publish_time = scrapy.Field()
    job_advantage = scrapy.Field()
    job_desc = scrapy.Field()
    job_addr = scrapy.Field(
    )
    company_name = scrapy.Field()
    company_url = scrapy.Field()
    tags = scrapy.Field(
        input_processor = Join(",")
    )
    crawl_time = scrapy.Field()


在这里代码基本编写完成,这里忽略了数据库的持久化,可以在知乎爬取那里学习,可以在cmd试着运行:cd进入项目目录后,输入:scrapy crawl lagou运行项目:

运行结果:  

如果没有爬取成功提示要登录,可以看看下面的应对措施

五,应对反爬措施

由于拉勾的反爬措施比较严格,所以可以会需要登录才可以访问,这里采取了反反爬虫的方法有:

5.1,设置随机的user-agent

首先导入 fake_useragent     :pip install  fake_usergent

然后在中间件 middlewares.py 添加以下代码:

from fake_useragent import UserAgent
#随机更换user-agent
class RandomUserAgentMiddlware(object):
    def __init__(self,crawler):
        super(RandomUserAgentMiddlware, self).__init__()
        self.ua = UserAgent()

    @classmethod
    def from_crawler(cls,crawler):
        return cls(crawler)

    def process_request(self,request,spider):
        request.headers.setdefault('User-Agent',self.ua.random)
这样每次下载页面时就会传入不同的 user-agent
别忘了在setting添加middlewares设置,否则该设置不生效
DOWNLOADER_MIDDLEWARES = {
   'ArticleSpider.middlewares.RandomUserAgentMiddlware': 543,
   'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
  
}




5.2,设置下载延迟
在setting中添加设置:
DOWNLOAD_DELAY = 10

这样基本就能爬取拉勾网大部分招聘信息了,如果还是不行,还能采取selenium驱动谷歌浏览器来访问,还可以设置自动登录,或者自动修改ip来解决,这里就不一一列举


六,问题

 
 
CrawlSpider如何工作的?

因为CrawlSpider继承了Spider,所以具有Spider的所有函数。 首先由start_requestsstart_urls中的每一个url发起请求(make_requests_from_url),这个请求会被parse接收。在Spider里面的parse需要我们定义,但CrawlSpider定义parse去解析响应(self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)_parse_response根据有无callback,followself.follow_links执行不同的操作

    def _parse_response(self, response, callback, cb_kwargs, follow=True):
    ##如果传入了callback,使用这个callback解析页面并获取解析得到的reques或item
        if callback:
            cb_res = callback(response, **cb_kwargs) or ()
            cb_res = self.process_results(response, cb_res)
            for requests_or_item in iterate_spider_output(cb_res):
                yield requests_or_item
    ## 其次判断有无follow,用_requests_to_follow解析响应是否有符合要求的link。
        if follow and self._follow_links:
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

其中_requests_to_follow又会获取link_extractor(这个是我们传入的LinkExtractor)解析页面得到的link(link_extractor.extract_links(response)),对url进行加工(process_links,需要自定义),对符合的link发起Request。使用.process_request(需要自定义)处理响应。






  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值