2018年 02月 05日 上午

  1k 字     4 分钟       

本爬虫仅供学习交流,请勿将爬取数据进行非法使用。

功能简介

本爬虫可爬取各大互联网行业常用招聘网站(目前包括 拉勾网、BOSS直聘、前程无忧、猎聘网,更多可自定义),采集职位主要信息输出到 csv 文件;
爬虫和文件写入独立两个进程(其实没必要,为了练习),进程A对每个网站的爬虫启动多线程,每个爬虫以生成器方式迭代返回数据,通过队列传输给进程B进行写入。

运行环境

  • Python 3
  • requests
  • lxml

代码简介

首先定义了爬虫的元类和基类,元类用来自动注册爬虫类到列表,进程只要遍历这个列表就能获得所有爬虫类了

# job_spider/spider.py

class SpiderMeta(type):
    """爬虫类的元类,注册子类到列表,爬虫类指定此元类才能加入进程"""

    spiders = []

    def __new__(mcs, name, bases, attrs):
        mcs.spiders.append(type.__new__(mcs, name, bases, attrs))
        return type.__new__(mcs, name, bases, attrs)

因为发现这些招聘网站对访问限制很高,所以在基类里实现了一个可以保持请求间隔和带默认 headers 的请求方法,每次请求都会计算与上次请求的间隔,间隔不够就等待,这样就不用每次 requests 后边都跟着 time.sleep 了;另外还加入了随机系数来对间隔进行浮动。

# job_spider/spider.py

class BaseSpider(object):
    """爬虫类的基类,提供需要的属性和方法"""

    # 省略部分代码

    def request(self, method='get', url=None, encoding=None, **kwargs):
        """
        根据爬虫类重新封装的`requests`,可保持请求间隔,并带有默认头部
        :param method: 请求方法,`get`或`post`等
        :param url: 请求链接
        :param encoding: 指定对返回对象进行编码
        :param kwargs: 其他`requests`自带的参数
        :return: Response 对象
        """
        # 没有指定头部则使用默认头部
        if not kwargs.get('headers'):
            kwargs['headers'] = self.headers
        # 随机生成系数对间隔产生变化
        rand_multi = random.uniform(0.8, 1.2)
        # 距离上次请求的间隔
        interval = time.time()-self._time_recode
        # 如间隔小于最短间隔,则进行等待
        if interval < self.request_sleep:
            time.sleep((self.request_sleep-interval)*rand_multi)
        resp = getattr(requests, method)(url, **kwargs)
        # 请求完重新记录时间戳
        self._time_recode = time.time()
        if encoding:
            resp.encoding = encoding
        return resp

爬虫具体代码就不说了,主要是实现一个crawl方法,用yield 返回数据。

下面是进程的代码,将元类列表的爬虫类分别传入iter_spider中,并启动一个线程即可。

# job_spider/process.py

class SpiderProcess(Process):
    """爬虫进程"""

    # 省略部分代码

    def iter_spider(self, spider):
        """对爬虫类的`crawl`方法进行迭代,数据送入队列传给另一进程"""
        setattr(spider, 'job', self.job)
        setattr(spider, 'city', self.city)
        generator = spider.crawl()
        if generator:
            for result in spider.crawl():
                self.data_queue.put(result)
                self.logger.debug('%s %s %50s...(省略)' % (result.get('title'), result.get('url'),
                                  result.get('description')))
        self.logger.info('%s 爬虫已结束' % spider.__class__.__name__)

    def run(self):
        """对每个爬虫类启动单独线程"""
        self.set_logging()
        spiders = [cls() for cls in SpiderMeta.spiders]
        spider_count = len(spiders)
        threads = []
        for i in range(spider_count):
            t = Thread(target=self.iter_spider, args=(spiders[i], ))
            t.setDaemon(True)
            t.start()
            threads.append(t)
        while True:
            time.sleep(1)

写数据进程比较简单,主要是按当前时间创建 csv 然后从队列里获取数据写入

# job_spider/process.py

class WriterProcess(Process):
    """写数据进程"""

    def __init__(self, data_queue):
        Process.__init__(self)
        self.data_queue = data_queue

    def run(self):
        """以当前时间创建 csv 文件,并从队列中获取数据写入"""
        csv_name = datetime.now().strftime('%Y-%m-%d %H-%M-%S') + '.csv'
        with open(csv_name, 'w', encoding='utf_8_sig', newline='') as f:
            writer = csv.writer(f)
            writer.writerow(['标题', '公司', '薪水', '经验',
                             '学历', '链接', '描述'])
            while True:
                try:
                    result = self.data_queue.get(timeout=90)
                    if result:
                        row = [
                            result.get('title'), result.get('company'),
                            result.get('salary'), result.get('experience'),
                            result.get('education'), result.get('url'),
                            result.get('description')
                        ]
                        writer.writerow(row)
                except queue.Empty:
                    f.close()

运行方式

方法一:使用命令行参数
$ python3 run.py -j 后端 -c 北京

方法二:直接运行,根据提示输入参数
$ python3 run.py

请输入职业:后端
请输入城市:北京

代码仓库

https://github.com/zkqiang/Job-Spider



Python 爬虫

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

 目录

关注公众号: 面向人生编程

回复【资料】获取精选学习资料