Python使用Scrapy框架爬取某网站职位数据并存放到MySQL数据库(支持二级页面爬取)

使用scrapy框架爬取数据入库mysql 第一次使用scrapy框架完成数据爬取 阅读详情

1、项目结构如下图所示,说明如下:

源代码工程文件下载地址:https://download.youkuaiyun.com/download/nosprings/12047437

spiderproject------项目工程目录

—spiderproject------爬虫主项目目录

——dao  ------ 数据库访问封装

———basedao.py ------ 数据库封装基础类

# 引入pymysql
import pymysql
import json
import logging
import os

class BaseDao(): # DAO: database access object

    def __init__(self, configFile='pymysql.json'):
        self.__connection = None
        self.__cursor = None
        self.__config = json.load(open(os.path.dirname(__file__) + os.sep + configFile, 'r'))  # 通过json配置获得数据的连接配置信息
        print(self.__config)
        pass

    # 获取数据库连接的方法
    def getConnection(self):
        # 当有连接对象时,直接返回连接对象
        if self.__connection:
            return self.__connection
        # 否则通过建立新的连接对象
        try:
            self.__connection = pymysql.connect(**self.__config)
            return self.__connection
        except pymysql.MySQLError as e:
            print("Exception:" + str(e))
            pass
        pass

    # 用于执行sql语句的通用方法 # sql注入
    def execute(self, sql, params):
        try:
            self.__cursor = self.getConnection().cursor()
            # result返回sql语句影响到的条数
            if params: # 带参数sql语句
                result = self.__cursor.execute(sql, params)
            else:      # 不带参数sql语句
                result = self.__cursor.execute(sql)
            return result
        except (pymysql.MySQLError, pymysql.DatabaseError, Exception) as e:
            print("出现数据库访问异常:" + str(e))
            self.rollback()
            pass
        finally:
            pass
        pass

    def fetch(self):
        if self.__cursor:
            return self.__cursor.fetchall()
        pass

    def commit(self):
        if self.__connection:
            self.__connection.commit()
        pass

    def rollback(self):
        if self.__connection:
            self.__connection.rollback()
        pass

    # 返回最后的自增主键
    def getLastRowId(self):
        if self.__cursor:
            return self.__cursor.lastrowid
        pass

    def close(self):
        if self.__cursor:
            self.__cursor.close()
        if self.__connection:
            self.__connection.close()
        pass

    pass


 

———jobpositiondao.py ------ 职位数据操作基本类文件

from .basedao import BaseDao

# 定义一个操作职位数据的数据库访问类
class JobPositionDao(BaseDao):

    def __init__(self):
        super().__init__()
        pass

    # 向数据库插入职位信息
    def create(self, params):
        sql = "insert into job_position (job_position, job_company, job_address, job_salary, job_date" \
              ",job_taskid, job_lowsalary,job_highsalary,job_meansalary,job_city) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
        result = self.execute(sql, params)
        lastRowId = self.getLastRowId()
        self.commit()
        return result, lastRowId
        pass

    def createDetail(self, params):
        sql = "insert into job_position_detail (detail_desciption, detail_positionid)"\
              "values (%s, %s)"
        result = self.execute(sql, params)  # ORM
        self.commit()
        return result
        pass

    def findPositionClassify(self):
        sql = 'select avg(job_meansalary), job_taskid, task_title from job_position, job_collect_task '+ \
              'where job_position.job_taskid=job_collect_task.task_id  group by job_taskid, task_title'
        result = self.execute(sql, params=None)
        self.commit()
        return self.fetch()
        pass

    def findCityPositionClassify(self):
        sql = 'select avg(t1.job_meansalary) as m, t1.job_taskid, t2.task_title ,t1.job_city from '+ \
                'job_position t1 left join job_collect_task t2 on t1.job_taskid = t2.task_id '+ \
                'group by job_taskid, job_city, t2.task_title order by t1.job_taskid asc, m desc'
        result = self.execute(sql, params=None)
        self.commit()
        return self.fetch()
        pass

    pass

———pymysql.json ------ 数据库访问基本配置文件

{"host":"127.0.0.1", "user":"root","password":"root", "database":"db_job_data", "port":3306, "charset":"utf8"}

———taskdao.py ------ 任务操作数据库操作

from .basedao import BaseDao

class TaskDao(BaseDao):

    def create(self, params):
        sql = "insert into job_collect_task (task_title, task_url) values (%s, %s)"
        result = self.execute(sql, params)
        lastRowId = self.getLastRowId()
        self.commit()
        self.close()
        return result, lastRowId
        pass
    pass

——spiders ------ 爬虫主文件目录

———jobspider.py ------ 爬虫主程序文件

# -*- coding: utf-8 -*-
import scrapy
from day22.spiderproject.spiderproject.items import SpiderprojectItem
import time

class JobspiderSpider(scrapy.Spider):
    name = 'jobspider'
    # allowed_domains = ['']
    # 访问的网址
    # start_urls = ['https://search.51job.com/list/000000,000000,0000,00,9,99,Python,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=']
    start_urls = []
    def __init__(self, start_urls=None, taskid=0, *args, **kwargs):
        super(JobspiderSpider, self).__init__(*args, **kwargs)
        self.start_urls.append(start_urls)
        self.taskid = taskid
        pass

    def parse(self, response):
        jobItems = response.xpath("//div[@class='el']") # 返回的是xpath的选择器列表
        # response.json()
        # 遍历选择器列表

        jobLen = len(jobItems)
        jobCount = 0

        nextURL = response.xpath('//li[@class="bk"]/a/@href').extract()  # 取下一页的地址
        nextText = response.xpath('//li[@class="bk"]/a/text()').extract()
        # print(nextURL)
        realURL = ""
        if nextURL and nextText[-1].strip() == '下一页':
            realURL = response.urljoin(nextURL[-1])
            pass

        for jobItem in jobItems:
            jobCount += 1
            sItem = SpiderprojectItem()
            sItem['taskId'] = self.taskid
            # 解析职位名称
            position = jobItem.xpath("p/span/a/text()")
            if position:
                sItem['jobPosition'] = position.extract()[0].strip()
                pass

            positionDetail = jobItem.xpath("p[@class='t1 ']/span/a/@href") # 返回的是选择器

            # 解析公司名称
            jobCompany = jobItem.xpath("span[@class='t2']/a/text()")
            if jobCompany:
                sItem['jobCompany'] = jobCompany.extract()[0].strip()
                pass
            # 解析地址
            jobAddress = jobItem.xpath("span[@class='t3']/text()")
            if jobAddress:
                sItem['jobAddress'] = jobAddress.extract()[0].strip()
                pass

            # 解析信息范围
            jobSalary = jobItem.xpath("span[@class='t4']/text()")
            if jobSalary:
                sItem['jobSalary'] = jobSalary.extract()[0].strip()
                pass

            # 解析分布日期
            jobDate = jobItem.xpath("span[@class='t5']/text()")
            if jobDate:
                sItem['jobDate'] = jobDate.extract()[0].strip()
                pass

            if position and jobCompany and jobAddress and jobSalary and jobDate and positionDetail:
                detailURL = positionDetail.extract()[0]

                sItem['nextURL'] = realURL

                yield scrapy.Request(url=detailURL, callback=self.parse_detail, meta={'item':sItem, 'jobLen':jobLen, 'jobCount':jobCount}, dont_filter=True)  # dont_filter是否去重复地址
                pass
            pass
        pass

    # 定义爬取详情页的方法
    def parse_detail(self, response):
        sItem = response.meta['item']
        jobLen = response.meta['jobLen']
        jobCount = response.meta['jobCount']
        detailData = response.xpath("//div[@class='bmsg job_msg inbox']")
        print('detailData:', detailData)
        if detailData:
            contents = detailData.xpath('//p/text()') # 返回当前选择器
            ct = ""
            if contents:
                for temp in contents.extract():
                    if temp.strip() == "" or  temp.strip() == "/":
                        continue
                    ct += temp + "\n"
                    pass
            sItem['jobDetail'] = ct
            yield sItem # 保顺序
            pass
        # 判断当前页是否爬取完成了,完成就继续爬取下一页
        if jobLen == jobCount:
            if sItem['nextURL']:
                yield scrapy.Request(sItem['nextURL'], self.parse, dont_filter=False)
            pass
        pass

    pass

——items.py ------ scrapy框架用来封装数据的实体类

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy

# 数据封装的实体类
class SpiderprojectItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    jobPosition = scrapy.Field()
    jobCompany = scrapy.Field()
    jobSalary = scrapy.Field()
    jobAddress = scrapy.Field()
    jobDate   = scrapy.Field()
    jobDetailURL = scrapy.Field()
    nextURL = scrapy.Field()
    jobDetail = scrapy.Field()
    taskId = scrapy.Field()
    pass

——middlewares.py ------ scrapy框架的中间件配置(例如下载器等)

# -*- coding: utf-8 -*-

# Define here the models for your spider middleware
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/spider-middleware.html

from scrapy import signals


class SpiderprojectSpiderMiddleware(object):
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the spider middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_spider_input(self, response, spider):
        # Called for each response that goes through the spider
        # middleware and into the spider.

        # Should return None or raise an exception.
        return None

    def process_spider_output(self, response, result, spider):
        # Called with the results returned from the Spider, after
        # it has processed the response.

        # Must return an iterable of Request, dict or Item objects.
        for i in result:
            yield i

    def process_spider_exception(self, response, exception, spider):
        # Called when a spider or process_spider_input() method
        # (from other spider middleware) raises an exception.

        # Should return either None or an iterable of Request, dict
        # or Item objects.
        pass

    def process_start_requests(self, start_requests, spider):
        # Called with the start requests of the spider, and works
        # similarly to the process_spider_output() method, except
        # that it doesn’t have a response associated.

        # Must return only requests (not items).
        for r in start_requests:
            yield r

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)


class SpiderprojectDownloaderMiddleware(object):
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        # Called for each request that goes through the downloader
        # middleware.

        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        return None

    def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.

        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response

    def process_exception(self, request, exception, spider):
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

——mysqlpiplines.py ------ 自定义用来向mysql数据库写入数据的管道

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html

from day22.spiderproject.spiderproject.dao.jobpostiondao import JobPositionDao

class SpiderMySqlPipeline(object):

    def process_item(self, item, spider):
        # 重用数据连接
        jobPositionDao = JobPositionDao()
        try:
            jobAddress = item['jobAddress']
            jobSalary = item['jobSalary']

            lowSalary = 0
            highSalary = 0
            meanSalary = 0
            # 获取地址信息中的城市信息
            jobCity = jobAddress.split('-')[0]

            # 处理薪资数据:1、判断单位
            if jobSalary.endswith('万/月'):
                jobSalary = jobSalary.replace('万/月', '')
                if jobSalary.find('-'):
                    salaryArray = jobSalary.split('-')
                    lowSalary = float(salaryArray[0]) * 10000
                    highSalary = float(salaryArray[1]) * 10000
                    pass
                else:
                    lowSalary = highSalary = float(jobSalary) * 10000
                meanSalary = (lowSalary + highSalary)/2
                pass
            elif jobSalary.endswith('千/月'):
                jobSalary = jobSalary.replace('千/月', '')
                if jobSalary.find('-'):
                    salaryArray = jobSalary.split('-')
                    lowSalary = float(salaryArray[0]) * 1000
                    highSalary = float(salaryArray[1]) * 1000
                    pass
                else:
                    lowSalary = highSalary = float(jobSalary) * 1000
                meanSalary = (lowSalary + highSalary)/2
                pass
            elif jobSalary.endswith('万/年'):
                jobSalary = jobSalary.replace('万/年', '')
                if jobSalary.find('-'):
                    salaryArray = jobSalary.split('-')
                    lowSalary = float(salaryArray[0]) * 10000 / 12
                    highSalary = float(salaryArray[1]) * 10000 / 12
                    pass
                else:
                    lowSalary = highSalary = float(jobSalary) * 10000 / 12
                meanSalary = (lowSalary + highSalary)/2
                pass
            elif jobSalary.endswith('元/天'):
                jobSalary = jobSalary.replace('元/天', '')
                if jobSalary.find('-'):
                    salaryArray = jobSalary.split('-')
                    lowSalary = float(salaryArray[0]) * 22
                    highSalary = float(salaryArray[1]) * 22
                    pass
                else:
                    lowSalary = highSalary = float(jobSalary) * 22
                meanSalary = (lowSalary + highSalary) / 2
                pass
            else:
                return

            result, lastRowId = jobPositionDao.create((item['jobPosition'], item['jobCompany'], item['jobAddress'], item['jobSalary'],
                                                       item['jobDate'], item['taskId'], lowSalary, highSalary, meanSalary, jobCity))
            if result:
                jobPositionDao.createDetail((item['jobDetail'], lastRowId))
                pass
        except Exception as e:
            print(e)
        finally:
            jobPositionDao.close()

        return item

——piplines.py ------ scrapy自动生成的管道

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


class SpiderprojectPipeline(object):
    def process_item(self, item, spider):
        print("通过管道输出数据")
        print(item['jobPosition'])
        print(item['jobCompany'])
        print(item['jobSalary'])
        print(item['jobAddress'])
        print(item['jobDate'])
        print(item['jobDetail'])

        return item

——rotateuseragent.py ------ scrapy框架来设置构造http请求头的代理

# -*- coding: utf-8 -*-"

# 导入random模块
import random
# 导入useragent用户代理模块中的UserAgentMiddleware类
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware

# RotateUserAgentMiddleware类,继承 UserAgentMiddleware 父类
# 作用:创建动态代理列表,随机选取列表中的用户代理头部信息,伪装请求。
#       绑定爬虫程序的每一次请求,一并发送到访问网址。

# 发爬虫技术:由于很多网站设置反爬虫技术,禁止爬虫程序直接访问网页,
#             因此需要创建动态代理,将爬虫程序模拟伪装成浏览器进行网页访问。
class RotateUserAgentMiddleware(UserAgentMiddleware):
    def __init__(self, user_agent=''):
        self.user_agent = user_agent

    def process_request(self, request, spider):
        #这句话用于随机轮换user-agent
        ua = random.choice(self.user_agent_list)
        if ua:
            # 输出自动轮换的user-agent
            print(ua)
            request.headers.setdefault('User-Agent', ua)

    # the default user_agent_list composes chrome,I E,firefox,Mozilla,opera,netscape
    # for more user agent strings,you can find it in http://www.useragentstring.com/pages/useragentstring.php
    # 编写头部请求代理列表
    user_agent_list = [\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1"\
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",\
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",\
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",\
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",\
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",\
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",\
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",\
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
       ]

——settings.py ------ 爬虫主配置文件

# -*- coding: utf-8 -*-

# Scrapy settings for spiderproject project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     https://docs.scrapy.org/en/latest/topics/settings.html
#     https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#     https://docs.scrapy.org/en/latest/topics/spider-middleware.html

BOT_NAME = 'spiderproject'

SPIDER_MODULES = ['spiderproject.spiders']
NEWSPIDER_MODULE = 'spiderproject.spiders'


# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'spiderproject (+http://www.yourdomain.com)'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 1
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16

# Disable cookies (enabled by default)
#COOKIES_ENABLED = False

# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False

# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
#   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
#   'Accept-Language': 'en',
#}

# Enable or disable spider middlewares
# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
SPIDER_MIDDLEWARES = {
    'spiderproject.middlewares.SpiderprojectSpiderMiddleware': 543,
}

# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
    'spiderproject.middlewares.SpiderprojectDownloaderMiddleware': 543,
    'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,  # 这一行是取消框架自带的useragent
    'spiderproject.rotateuseragent.RotateUserAgentMiddleware': 400
}

# Enable or disable extensions
# See https://docs.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
#    'scrapy.extensions.telnet.TelnetConsole': None,
#}

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'spiderproject.pipelines.SpiderprojectPipeline': 300,
    'spiderproject.mysqlpipelines.SpiderMySqlPipeline': 301,  # 配置自己的管道
}

# Enable and configure the AutoThrottle extension (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
AUTOTHROTTLE_DEBUG = False

# Enable and configure HTTP caching (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

# 配置日志新的输出
LOG_LEVEL = 'ERROR'
LOG_FILE = 'jobspider.log'

—scrapy.cfg ------ 工程配置文件

# Automatically created by: scrapy startproject
#
# For more information about the [deploy] section see:
# https://scrapyd.readthedocs.io/en/latest/deploy.html

[settings]
default = spiderproject.settings

[deploy]
#url = http://localhost:6800/
project = spiderproject

—startspider.py ------ 爬虫启动文件

# 此脚本是爬虫启动脚本
from scrapy.cmdline import execute
from  day22.spiderproject.spiderproject.dao.taskdao import TaskDao
# 启动爬虫
td = TaskDao()
result, taskId = td.create(('Python职位数据采集','https://search.51job.com/list/000000,000000,0000,00,9,99,Python,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='))

if result:
    execute(['scrapy', 'crawl', 'jobspider',
             '-a', 'start_urls=https://search.51job.com/list/000000,000000,0000,00,9,99,Python,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=',
             '-a', 'taskid=' + str(taskId)])
    pass
#
# result, taskId = td.create(('Java职位数据采集','https://search.51job.com/list/000000,000000,0000,00,9,99,java,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='))
# if result:
#     execute(['scrapy', 'crawl', 'jobspider',
#              '-a', 'start_urls=https://search.51job.com/list/000000,000000,0000,00,9,99,java,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=',
#              '-a', 'taskid=' + str(taskId)])
#     pass

'''
execute(['scrapy', 'crawl', 'jobspider',
         '-a', 'start_urls=https://search.51job.com/list/000000,000000,0000,00,9,99,%25E4%25BA%25BA%25E5%25B7%25A5%25E6%2599%25BA%25E8%2583%25BD,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=',
         '-a', 'taskid=2',
         '-a', 'paramName=paramValue'])
'''

2、数据库结构如下:

 

CREATE DATABASE  IF NOT EXISTS `db_job_data` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `db_job_data`;
-- MySQL dump 10.13  Distrib 5.7.17, for Win64 (x86_64)
--
-- Host: localhost    Database: db_job_data
-- ------------------------------------------------------
-- Server version	5.7.22

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `job_collect_task`
--

DROP TABLE IF EXISTS `job_collect_task`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `job_collect_task` (
  `task_id` int(11) NOT NULL AUTO_INCREMENT,
  `task_title` varchar(128) DEFAULT NULL,
  `task_url` varchar(1024) DEFAULT NULL,
  `task_date` datetime DEFAULT CURRENT_TIMESTAMP,
  `task_total` int(11) DEFAULT NULL,
  `task_state` int(11) DEFAULT '1',
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `job_dept`
--

DROP TABLE IF EXISTS `job_dept`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `job_dept` (
  `dept_id` int(11) NOT NULL,
  `dept_name` varchar(45) DEFAULT NULL,
  `dept_parentid` int(11) DEFAULT NULL,
  PRIMARY KEY (`dept_id`),
  UNIQUE KEY `dept_name_UNIQUE` (`dept_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `job_position`
--

DROP TABLE IF EXISTS `job_position`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `job_position` (
  `job_id` int(11) NOT NULL AUTO_INCREMENT,
  `job_position` varchar(512) DEFAULT NULL,
  `job_company` varchar(512) DEFAULT NULL,
  `job_address` varchar(512) DEFAULT NULL,
  `job_salary` varchar(45) DEFAULT NULL,
  `job_date` varchar(45) DEFAULT NULL,
  `job_taskid` int(11) DEFAULT NULL,
  `job_degree` varchar(45) DEFAULT NULL,
  `job_expyear` varchar(45) DEFAULT NULL,
  `job_lowsalary` float DEFAULT NULL,
  `job_highsalary` float DEFAULT NULL,
  `job_meansalary` float DEFAULT NULL,
  `job_city` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`job_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2093 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `job_position_detail`
--

DROP TABLE IF EXISTS `job_position_detail`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `job_position_detail` (
  `detail_id` int(11) NOT NULL AUTO_INCREMENT,
  `detail_desciption` longtext,
  `detail_positionid` int(11) DEFAULT NULL,
  PRIMARY KEY (`detail_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2093 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `job_user`
--

DROP TABLE IF EXISTS `job_user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `job_user` (
  `USER_ID` int(11) NOT NULL AUTO_INCREMENT,
  `USER_NAME` varchar(32) NOT NULL,
  `USER_PWD` varchar(512) NOT NULL,
  `USER_AGE` int(11) DEFAULT NULL,
  `USER_SEX` int(11) DEFAULT NULL,
  `USER_QQ` int(11) DEFAULT NULL,
  `USER_CELLPHONE` varchar(20) DEFAULT NULL,
  `USER_MONEY` float DEFAULT NULL,
  `USER_STATUS` int(11) DEFAULT '1',
  `USER_PIC` varchar(128) DEFAULT NULL,
  `USER_INTRO` longtext,
  `USER_BIRTH` datetime DEFAULT NULL,
  `USER_DEPTID` int(11) DEFAULT NULL,
  `USER_ROLE` int(11) DEFAULT '1',
  PRIMARY KEY (`USER_ID`),
  UNIQUE KEY `USER_NAME_UNIQUE` (`USER_NAME`)
) ENGINE=InnoDB AUTO_INCREMENT=3595 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2019-12-23 16:50:55

 

 

Python 爬虫与 Scrapy 实战:批量抓取招聘网站职位信息 本教程介绍了使用Scrapy框架抓取招聘网站职位信息的方法,以猎云网为例展示了完整流程。首先安装Scrapy并创建项目,然后编写爬虫代码提取职位信息(标题、公司、地点、薪资等),配置参数优化爬取效率,最后将数据存储为JSON文件或数据库。文章还提供了提高爬虫稳定性的建议,如使用代理池、请求延时等,适合需要批量获取招聘信息的开发者参考。 阅读详情

相关推荐

Python Scrapy实战:抓取腾讯招聘数据,掌握反爬与数据存储

网络爬虫是自动化获取互联网公开数据的关键技术,其核心原理是通过模拟浏览器行为向目标服务器发送请求并解析响应内容。在数据分析、市场研究和求职规划等场景中,爬虫技术能高效地采集海量、实时的结构化信息,为决策提供数据基础。Scrapy作为Python生态中强大的异步爬虫框架,通过其模块化的架构(Spider、Item、Pipeline、Middleware)提供了完整的解决方案,尤其擅长处理复杂的动态网页和应对反爬机制。本次实战项目以抓取腾讯招聘官网数据为例,深入演示了如何分析AJAX接口、构造模拟请求、处理动态

weixin_33743703的博客 423

Scrapy爬取数据并存储到MySQL

Scrapy爬虫 爬虫框架 架构 流程 组件 功能 同步插入数据库 异步插入数据库 mysql pipeline

一个人的编程之路 8868

基于Python的多线程异步爬虫实现:招聘网站职位信息爬取与就业趋势分析

本文详细介绍了一个基于Python的招聘网站数据爬取与分析系统,采用Scrapy-Redis分布式爬虫框架结合Playwright无头浏览器技术,实现了对主流招聘网站的大规模数据采集。系统包含数据爬取、数据清洗、存储和分析四个核心模块,利用多线程、异步IO和分布式技术提高了爬取效率,并通过MongoDB进行数据存储,最终使用PySpark和Matplotlib进行就业市场趋势分析。本文提供了完整的实现代码和详细的技术方案,为就业市场研究提供了数据支持。关键词:Python爬虫;Playwright;

2201_76125261的博客 877

探索TanJunChen的Spider-Project:高效爬虫框架的奥秘

探索TanJunChen的Spider-Project:高效爬虫框架的奥秘 去发现同类优质开源项目:https://gitcode.com/ 在这个数字信息爆炸的时代,数据是驱动决策的关键要素。 是一个由 TanJunChen 开发的Python爬虫框架,旨在帮助开发者更高效、便捷地抓取和处理网络上的大量数据。本文将深入探讨这个项目的原理、用途及其独特之处,以期激发你对数据采集的热情。 项目简介 ...

gitblog_00030的博客 492

python爬虫项目(一百八十八):招聘网站企业信息爬取及行业分析、爬取招聘网站企业信息

快速高效:能够并行处理请求。强大的选择器:支持XPath和CSS选择器,便于解析网页。可扩展性强:可通过中间件和扩展功能自定义。

斌擎科技 1605

基于Python3与Scrapy的腾讯招聘信息爬取实战项目

为了让爬虫真正“无人值守”,我们可以写个 Shell 脚本配合 crontab 每天自动运行:/bin/bash# 出错发邮件提醒thenfi添加定时任务:# 每天凌晨2点执行从此,每天醒来都能看到最新的招聘数据静静躺在数据库里,仿佛有个隐形助手彻夜工作……😎回顾整个过程,我们用了不少技术:异步、XPath、中间件、分布式、代理池……但真正让系统长久运行下去的,从来不是某项黑科技,而是两个字——尊重。尊重网站的服务器负载,所以设了延时;

weixin_35706255的博客 1017

『scrapy爬虫』05. 使用管道将数据写入mysql(详细注释步骤)

『scrapy爬虫』05. 使用管道将数据写入mysql(详细注释步骤)

MZH 1725

爬虫项目Spider-project 爬虫实战项目

文件列表: 1-源码乱码 (0, 2023-02-05) 1-源码乱码\hex_md5.js (7339, 2023-02-05) 1-源码乱码\top-1.js (2474, 2023-02-05) 1-源码乱码\猿人学第一题.py (1264, 2023-02-05) 12-入门级js (0, 2023-02-05) 12-入门级js\猿人学第12题.py (1538, 2023-02-05) 13-入门cookie (0, 2023-02-05) 13-入门cookie\猿人学第13题.py (763, 2023-02-05) 15-备周则意怠 (0, 2023-02-05) 15-备周则意怠\main.wasm (3854, 2023-02-05) 15-备周则意怠\猿人学第15题.py (1545, 2023-02-05) 17-天杀的http2 (0, 2023-02-05) 17-天杀的http2\yuanrenxue_17.py (1198, 2023-02-05) 19-乌拉乌拉乌拉 (0, 2023-02-05) 19-乌拉乌拉乌拉\yuanrenxue-19.py

基于scrapy框架的腾讯招聘信息网络爬虫设计与实现

摘要:随着网络科技技术的快速增长,网络数据已经成为一种极其重要的资源。如今的一个研究热点是如何快速和有效率地寻找、提取、分析数据。对于这些方法,运用Python的Scrapy框架可以设计出网络爬虫,对网络数据进行提取分析。先分析网站源代码,之后设计出相应的表达式来提取需要用到的数据,提取结束之后将数据保存进数据库里。本课题是一个基于scrapy分布式爬虫针对腾讯招聘网站数据的抓取系统,为数据进一步操作做数据支持。

QQ2743785109的博客 1905

课程复习---分析空间数据的细胞空间关系(python版本的mistyR)

课程复习---分析空间数据的细胞空间关系(python版本的mistyR)

weixin_53637133的博客 1222

从RTL到GDSII:DC综合里那些没人告诉你的时钟约束冷知识(附真实工程示例)

本文深入探讨数字IC设计中DC综合阶段的时钟约束冷知识,包括无毛刺时钟切换、寄存器分频时钟约束、虚拟时钟应用等关键技巧。通过真实工程示例,揭示常见约束误区及解决方案,帮助工程师提升时序收敛效率。特别针对input_delay和output_delay在多时钟域场景下的设置陷阱提供实用指南。

weixin_29306317的博客 429

基于Python的涉农职位招聘信息爬取与可视化分析

摘要:本系统是基于Python的涉农职位招聘信息分析与可视化平台,采用B/S架构和微服务设计。系统通过Scrapy框架爬取主流招聘网站数据,经Pandas清洗后存储在MongoDB中,使用ECharts实现可视化分析。核心功能包括数据采集、清洗转换、交互式仪表盘和多维度分析报告,专注于农业领域招聘市场分析。特色在于建立农业专属分类体系、支持10+维度交叉分析,并提供拖拽式配置和自动报告生成,帮助求职者、教育机构、政府部门和企业HR获取精准的农业人才市场洞察。系统部署于阿里云,采用Nginx+uWSGI架构,

2501_93059031的博客 504

MATLAB小白也能搞定!BCT脑网络分析工具箱安装与入门指南

本文为零基础用户提供了一份详尽的BCT脑网络分析工具箱安装与入门指南。从MATLAB环境配置、BCT工具箱下载与路径添加,到连接矩阵构建、节点度与聚类系数等基础指标计算,手把手带领神经科学研究者跨越编程门槛,快速掌握脑影像数据分析的核心流程。

threejs5artist的博客 1092

基于爬虫技术的网络数据岗位职位招聘求职信息采集管理系统可视化

用户功能爬取招聘数据: 自动获取网络上的招聘信息,涵盖职位名称、工作地点、薪资范围、公司名称和职位要求等。(爬取BOOS直聘网站)热门岗位展示: 分析市场需求,展示热门岗位。推荐岗位: 根据用户偏好和搜索历史推荐职位。自动回复: 对用户咨询提供自动回复功能。首页: 展示系统概览和用户功能入口。公告讨论区: 用户和管理员交流的平台。管理员功能系统概览: 展示系统状态和最新爬取的职位信息。职位列表: 展示所有爬取的职位信息,支持搜索和过滤。

QQ58850198的博客 1707

汽车电子开发必看:AUTOSAR MCAL层SPI驱动配置全解析(基于EB tresos)

本文深入解析了AUTOSAR MCAL层SPI驱动的核心配置,基于EB tresos工具详细阐述了通道、外部设备、作业与序列等关键概念。重点剖析了多设备共享总线时的资源管理与实时性调优策略,特别是SpiJobPriority参数的决定性影响,并提供了常见配置陷阱的实战排查指南,旨在帮助汽车电子工程师高效完成SPI驱动配置。

weixin_29188043的博客 293

Tableau学习教程(万字保姆级教程)​​​​​​

​Tableau学习教程(保姆级教材,学不会私信留言来找我) 从BI系统开发的角度来学习tableau工具,更学会报表开发的流程 内含学习使用数据源,tableau打包工作簿,可直接提取使用 ​...

小菜菜的博客 6万+

基于Scrapy的拉勾网招聘数据爬取与Python数据分析实战

网络爬虫是自动化获取互联网公开数据的关键技术,其核心原理是通过模拟浏览器请求,解析网页结构,从而高效提取结构化信息。在数据驱动的决策时代,这项技术为市场分析、竞品研究和趋势洞察提供了宝贵的数据源。Scrapy作为Python生态中强大的异步爬虫框架,凭借其高性能、易扩展和工程化的特性,成为处理大规模、结构化数据抓取的理想选择。结合Pandas进行数据清洗与转换,以及Matplotlib和Seaborn进行可视化分析,可以构建从数据采集到洞察呈现的完整闭环。本文以拉勾网招聘数据为具体应用场景,详细阐述了如何利

weixin_33985679的博客 356

SAP ABAP 如何实现物料主数据接口的增量传输机制?

如何实现物料主数据接口的增量传输机制?我在各客户系统中看到了五花八门的实现方式,即使是 IBM 实施的开发质量也并没有保证。其实这是一个很简单的问题,下面以物料主数据接口为例子,介绍 SAP 中更改文档对象的接口数据增量传输机制。

SAP李斌,本人承诺所有原创文章均不使用任何AI生成技术,请大家放心阅读。 1316

基于python数据挖掘技术的线上招聘信息数据可视化分析系统 q3122-- Scrapy爬虫

基于数据挖掘技术的线上招聘信息分析系统旨在通过应用先进的数据分析方法,为求职者和招聘者提供更加高效、精准的招聘服务。该系统具备强大的信息处理能力,能够从海量的招聘数据中提取有价值的信息,揭示市场趋势和职位需求。管理员则可以通过用户管理和招聘信息管理模块,维护系统的正常运行,确保信息的准确性和时效性。系统还利用数据挖掘技术对招聘信息进行深度分析,为招聘者提供有关求职者偏好、职位竞争情况等重要洞察,从而优化招聘策略。总体而言,该系统通过数据挖掘技术的应用,为招聘市场带来了更加智能化和个性化的服务体验。

豆包程序员 1297

图文教程本地部署开源扣子Coze Studio工作流并接入 Gemini 大模型(windows亲测) Coze Studio 本地部署、Gemini 模型接入、开源 AI 工具平台、大模型工作流搭建

本文介绍了在Windows系统本地部署开源AI工具平台Coze Studio并接入Google Gemini大模型的完整教程。主要内容包括:1) 环境准备要求(Docker等);2) 获取源码和配置Gemini模型(需API密钥);3) 通过Docker Compose部署服务;4) 浏览器访问验证。文章指出该平台适合私有化部署,支持智能体和工作流搭建,但也存在插件系统不完善等局限。最后提供了相关资源链接,为开发者实现本地AI解决方案提供了实用指南。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 2780

18、AI在基础设施管理与运维中的应用及未来趋势

本文探讨了人工智能(AI)在基础设施管理和运维中的广泛应用,包括性能优化、成本节约、网络安全等多个场景。文章详细介绍了AI在不同领域的应用工具、实际案例以及面临的挑战,并展望了未来AI在基础设施管理中的发展趋势。此外,还分析了AI与Site Reliability Engineering(SRE)框架的结合优势,展示了AI如何提升运维效率和系统可靠性。

n7o8p的博客 148

基于python的招聘数据爬虫设计与实现

本项目设计并实现了一个基于Python的招聘数据爬虫系统,通过Scrapy框架高效抓取并解析了多个招聘网站的职位信息。系统不仅包括数据抓取、解析、存储的核心流程,还考虑了数据清洗、异常处理等细节,确保数据的质量与完整性。此外,通过引入简单的前端展示,提高了数据的可访问性和实用性。该系统能够为人力资源分析、求职者市场研究等提供坚实的数据基础,同时也展示了Python在数据采集领域的强大能力。

weixin_32121949的博客 1299

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

scrapy 智联 mysql_scrapy 爬取智联招聘

#-*- coding: utf-8 -*-importosimportjsonfrom tinydb importTinyDB, Queryfrom furl importfurlimportscrapyclassZhaopinspiderSpider(scrapy.Spider):name= 'ZhaopinSpider'allowed_domains= ['www.zhaopin.com',...

weixin_39860757的博客 98

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Scrapy框架实战:Python爬虫开发与优化指南

网络爬虫作为数据采集的核心技术,其实现方式从简单的requests脚本到分布式爬虫框架不断演进。Scrapy作为Python生态中最成熟的爬虫框架,采用异步IO架构和模块化设计,能高效处理动态网页抓取、反爬对抗等复杂场景。框架内置的请求调度、中间件系统和数据处理管道,特别适合需要遵守robots.txt规则的合规爬取,以及应对动态加载内容的现代网站。通过配置代理IP池和随机UserAgent等反爬策略,结合MongoDB等灵活存储方案,可构建日均百万级抓取量的稳定爬虫系统。本文以招聘网站数据采集为例,详解S

weixin_30562507的博客 342

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

django基于Python的IT招聘数据可视化分析系统 Scrapy爬虫毕业设计

随着互联网技术不断地发展,网络与大数据成为了人们生活的一部分,而IT招聘数据分析及可视化作为网上应用的一个全新的体现,由于其特有的便捷性,已经被人们所接受。目前主流的IT招聘数据分析及可视化服务不仅不明确并且管理盈利较低,针对招聘定制的IT招聘数据分析及可视化更能够体现出其服务特色。本项目以IT招聘数据分析及可视化为研究背景,采用的框架为Vue和python开发了IT招聘数据分析及可视化。

懒人的博客 1944

python-django 招聘数据可视化系统

本项目主要利用python技术爬取51job直聘网站上的岗位信息。爬取字段:工作地点,薪资范围,学历要求,工作经验,公司性质等。爬取相关信息下载网页源码,采用scarpy来提取数据,存储到数据库,以柱状图或饼状图形式对数据进行可视化分析得出结论。51job招聘信息采集可视化系统是一种集成了爬虫、数据存储和数据可视化等功能的Web应用程序,主要用于采集51job网站上的招聘信息,并通过可视化图表展示这些信息,以帮助用户更加方便地了解企业招聘行情、职位需求等信息。登入注册职位数据可视化。

britlee的博客 529
上一篇: window下安装MySQL5.7解压缩版本并且修改密码,卸载命令sc delete mysql
下一篇: Java入门基础:Java使用JFrame开发出漂亮的桌面程序附源码下载(谁说Java不可以开发出漂亮的界面)
猿说猿道
博客等级 码龄8年 120粉丝 55原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值