招聘网站Spider

# -*- coding: utf-8 -*-
import os
import logging

import requests
from queue import Queue
from bs4 import BeautifulSoup

#==============================================================================
# 开始url
#==============================================================================
START_URL = (
    "http://search.51job.com/list/010000%252C020000%252C030200%252C040000"
    ",000000,0000,00,9,99,Python,2,{}.html? lang=c&stype=1&postchannel=00"
    "00&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&lon"
    "lat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=1&dibiaoid=0&"
    "address=&line=&specialarea=00&from=&welfare="
)
urls = [START_URL.format(p) for p in range(1, 16)]
#用数字替换了URL中的{}部分,共爬取15页



HEADERS = {
    "X-Requested-With": "XMLHttpRequest",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36"
    "(KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
}

def get_logger():
    """
    创建日志实例
    """
    formatter = logging.Formatter("%(asctime)s - %(message)s")
    logger = logging.getLogger("monitor")
    logger.setLevel(LOG_LEVEL)

    ch = logging.StreamHandler()
    ch.setFormatter(formatter)
    logger.addHandler(ch)
    return logger    
    
LOG_LEVEL = logging.INFO    # 日志等级
logger = get_logger()


count = 1  # 记录当前爬第几条数据
company = []    #存放公司信息
desc_url_queue = Queue()  # 线程池队列
#pool = Pool(POOL_MAXSIZE)  # 线程池管理线程,最大协程数
#==============================================================================
# 开始爬取公司
#==============================================================================
for url in urls:
    logger.info("爬取第 {} 页".format(urls.index(url) + 1))
    html = requests.get(url, headers=HEADERS).content.decode("gbk")
    bs = BeautifulSoup(html, "lxml").find("div", class_="dw_table").find_all(
        "div", class_="el"
    )
    for b in bs:
        try:
            href, post = b.find("a")["href"], b.find("a")["title"]
            locate = b.find("span", class_="t3").text
            salary = b.find("span", class_="t4").text
            item = {
                "href": href, "post": post, "locate": locate, "salary": salary
            }
            desc_url_queue.put(href)  # 岗位详情链接加入队列
            company.append(item)
        except Exception:
            pass
# 打印队列长度,即多少条岗位详情 url
logger.info("队列长度为 {} ".format(desc_url_queue.qsize()))

#==============================================================================
# #得到了company信息list 
#==============================================================================

def post_require():
    """
    爬取职位描述
    """
    count = 1  # 记录当前爬第几条数据
    while True:
        # 从队列中取 url
        url = desc_url_queue.get()
        resp = requests.get(url, headers=HEADERS)
        if resp.status_code == 200:
            logger.info("爬取第 {} 条岗位详情".format(count))
            html = resp.content.decode("gbk")
            desc_url_queue.task_done() #队列清空 
#            在完成一项工作之后,queue.task_done()函数向任务已经完成的队列发送一个信号

            count += 1
        else:
            desc_url_queue.put(url)
            continue
        try:
            bs = BeautifulSoup(html, "lxml").find(
                "div", class_="bmsg job_msg inbox"
            ).text
            s = bs.replace("微信", "").replace("分享", "").replace("邮件", "").replace(
                "\t", ""
            ).strip()
            with open(
                os.path.join("data", "post_require.txt"), "a", encoding="utf-8"
            ) as f:
                f.write(s)
        except Exception as e:
            logger.error(e)
            logger.warning(url)
        if desc_url_queue.empty():
            print('队列长度'+str(desc_url_queue.qsize()))
            break
#==============================================================================
#  #获取上一步desc_url_queue队列里每个页面的岗位详情           
#==============================================================================
post_require() 

python Queue的多线程应用

queue.Queue

Queue类实现了一个基本的先进先出(FIFO)容器,使用put()将元素添加到序列尾端,get()从队列尾部移除元素.

q = Queue()

for i in range(3):
    q.put(i)
 
while not q.empty():
    print(q.get())

gevent.pool

Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。

gevent是第三方库,通过greenlet实现协程,其基本思想是:

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成:
Pool
中提供了如下几个方法:

apply()
apply_async()
map()
map_async()
close()
terminal()
join()

遇到阻塞队列 线程不结束

队列是线程间最常用的交换数据的形式。Queue模块是提供队列操作的模块,虽然简单易用,但是不小心的话,还是会出现一些意外。

“ gevent.hub.LoopExit: This operation would block forever”

解决。避免使用gevent https://www.cnblogs.com/cjaaron/p/9178083.html

<think>好的,我现在需要帮助用户寻找使用Scrapy框架编写的招聘网站爬虫源码,特别是GitHub上的示例代码。首先,我应该回忆一下用户提供的引用内容,看看有没有相关的信息。用户提供的引用中有几个关于Scrapy创建项目和爬虫的示例,比如引用[1]、[2]、[3]都提到了如何创建Scrapy项目,生成爬虫,以及目录结构。特别是引用[2]中的代码示例,用户创建了一个名为zhaoping的项目,爬虫名字是hr,允许的域名是zhaopingwang.com。这可能是一个招聘网站的爬虫示例。此外,引用[4]展示了如何发送POST请求,处理JSON数据,这对招聘网站爬虫可能有帮助,因为有些网站使用POST请求来获取数据。接下来,我需要考虑用户的需求是寻找GitHub上的Scrapy招聘爬虫源码。我应该回忆常见的GitHub资源,或者提供一些搜索建议。例如,用户可以使用GitHub的搜索功能,输入关键词如“scrapy jobsitecrawler”或“scrapy recruitmentspider”,然后按Stars或最近更新排序,找到高质量的项目。此外,用户可能需要代码示例的结构,所以我可以根据引用中的内容,整理一个简单的Scrapy爬虫框架,比如如何定义Item,编写Spider,处理请求和响应,以及存储数据到数据库。引用[2]中的items.py和pipelines.py部分可以作为参考,定义职位名称、地点、发布日期等字段,并使用MongoDB存储。同时,需要注意招聘网站的反爬机制,比如设置下载延迟、使用User-Agent轮换,或者处理动态内容。引用[4]中的POST请求处理也是一个重点,因为很多招聘网站通过API返回JSON数据,需要构造正确的请求头和载荷。最后,生成相关问题,帮助用户进一步深入,比如如何应对反爬措施,处理分页,或者数据清洗。这样用户不仅能找到源码示例,还能了解实际开发中的常见问题和解决方案。</think>以下是为您整理的Scrapy招聘网站爬虫实现方案及参考资源: ### 一、基础爬虫结构示例 ```python # spiders/hr_spider.py import scrapy from scrapy.http import FormRequest class ZhaopinSpider(scrapy.Spider): name = 'zhaopin' allowed_domains = ['zhaopin.com'] def start_requests(self): url = 'https://www.zhaopin.com/job/search' # 模拟POST请求(参考引用[4]) yield scrapy.FormRequest( url=url, formdata={ 'keyword': 'Python', 'pageIndex': '1', 'pageSize': '20' }, callback=self.parse ) def parse(self, response): # 提取职位信息 for job in response.css('div.job-list li'): yield { 'title': job.css('h3::text').get(), 'company': job.css('.company-name::text').get(), 'salary': job.css('.salary::text').get(), 'location': job.css('.job-location::text').get(), 'url': response.urljoin(job.css('a::attr(href)').get()) } # 分页处理(参考引用[3]) next_page = response.css('a.next-page::attr(href)').get() if next_page: yield response.follow(next_page, self.parse) ``` ### 二、GitHub资源搜索建议 1. 搜索关键词建议: - `scrapy job site crawler` - `scrapy recruitment spider` - `scrapy zhaopin lagou` 2. 优质项目特征: - 包含`items.py`完整字段定义(参考引用[2]) - 使用`middlewares.py`处理反爬 - 包含`pipelines.py`数据库存储(参考引用[2]中的MongoDB示例) - 最近1年内有更新 ### 三、关键组件实现参考 1. **Item定义**(参考引用[2]): ```python # items.py class JobItem(scrapy.Item): title = scrapy.Field() company = scrapy.Field() salary = scrapy.Field() location = scrapy.Field() requirements = scrapy.Field() publish_date = scrapy.Field() ``` 2. **反爬处理**: ```python # settings.py DOWNLOAD_DELAY = 2 ROBOTSTXT_OBEY = False USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' ``` 3. **数据存储**(参考引用[2]): ```python # pipelines.py import pymongo class MongoPipeline: def open_spider(self, spider): self.client = pymongo.MongoClient('mongodb://localhost:27017') self.db = self.client['job_db'] def process_item(self, item, spider): self.db[spider.name].insert_one(dict(item)) return item ``` ### 四、注意事项 1. 遵守目标网站的`robots.txt`协议 2. 处理动态加载内容时建议配合`scrapy-splash`或`selenium` 3. 加密参数处理(如智联招聘的`secretKey`) 4. 频率控制避免触发反爬(参考引用[4]的请求间隔设置)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值