详解scrapy爬取赶集网简历数据实现下一页并保存至csv文件详细入门实例

第一次写CSDN的博客

  • 闲话

相信大家和我以前一样,遇到问题呢就百度,而大多数提供有效解决方案的就是CSDN博客。
或许,在过去我们的积累还不够,没水平没脸在这么高大上的博客上发布文章。
还有一个原因我觉得是最普遍的,就是我们做一个事情然后不断解决问题直到成功,然后就不去管它了,我们已经从中吸取了知识,再用博客写一遍呢白白浪费时间。
无论如何,今天我还是想发布一篇博客分享给大家,这篇文章技术含量不是很高,大牛请绕道

  • 现在进入正题

  • 首先安装scrapy,pip install scrapy,这个就不多说了。

  • 由于scrapy框架是面向程序员的,因此有很多操作在命令行,这个时候你就需要一个称手的编辑器来编辑你的代码,我这里使用的是VS code,配置的python环境。里面有很多好用的python扩展包,大家需要自行百度。

  • 第一步就是确定好爬取目标,此次目标网址是
    http://www.ganji.com/findjob/resume_list.php?city=194&type=1&major=qzjisuanjiwangluo&tag=&intval1=&key=%E5%85%B6%E4%BB%96%E8%81%8C%E4%BD%8D&open=1&sex=&period=&age=&age_start=&age_end=&edu=&pay=&parttime_pay=&time=

  • 第二步创建一个爬虫项目
    scrapy startproject resume(文件夹)
    然后在文件夹里面有一个同名文件夹和一个cfg文件(csv文件是我自己新建用来存放简历数据的)
    resume文件夹
    子resume文件夹里面有这些文件,scrapy自动生成的

  • 第三步,命令行里cd进入resume文件夹,创建一个爬虫
    scrapy genspider re_spider www.ganji.com
    re_spider是爬虫名字,以后运行爬虫的标识符
    后面网址限定爬虫范围,以后可以改没关系
    编写完代码,运行爬虫的命令:
    scrapy crawl re_spider

  • 第四步就开始写代码了
    首先给大家简单介绍这几个py文件的作用
    1、items.py定义项目用到的item类,类字典类型
    2、pipelines.py负责处理爬取到的信息
    3、settings.py项目配置文件,进行项目相关配置
    4、spiders文件夹中用爬虫名命名的re_spider.py就是你爬虫代码编写的位置
    5、其他没提到的是你目前不需要管的

编写items.py文件

这里定义你需要爬取的几个数据。
比如我爬取姓名,性别,年龄,学历,工作年限,期望薪资等

class ResumeItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field()
    sex = scrapy.Field()
    age = scrapy.Field()
    edu = scrapy.Field()#学历
    exp =scrapy.Field()#工作年限
    salary =scrapy.Field()#期望薪资
    pass

编写核心代码re_spider.py

这里可能用到的知识有:
正则表达式
css selector
xpath
此网页用xpath很合适,记得导入ResumeItem类,并且实例化 item = ResumeItem(),代码如下:

# -*- coding: utf-8 -*-
import scrapy
import requests
from lxml import etree
from resume.items import ResumeItem
import time

class ReSpiderSpider(scrapy.Spider):
    name = 're_spider'
    allowed_domains = ['www.ganji.com']
    start_urls = ['http://www.ganji.com/findjob/resume_list.php?city=194&type=1&major=qzjisuanjiwangluo&tag=&intval1=&key=%E5%85%B6%E4%BB%96%E8%81%8C%E4%BD%8D&open=1&sex=&period=&age=&age_start=&age_end=&edu=&pay=&parttime_pay=&time=']

    def parse(self, response):
        item = ResumeItem()

        item['name'] = response.xpath('//html/body/div[3]/div[2]/dl/dt/a/text()').extract()
        item['sex'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[2]/text()').extract()
        item['age'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[3]/text()').extract()
        item['edu'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[5]/text()').extract()
        item['exp'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[6]/text()').extract()
        item['salary'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[4]/text()').extract()
        yield item

这里有个问题要注意一下,关于scrapy框架的理解,就是response对象它返回什么?它是什么类型?为什么能这样使用response.xpath()
如果有疑问,说明你有基本的编程思维,看看这篇文章给你解答
scrapy中的response对象

  • 程序还没有完
    以上代码只爬取了以上链接的一个页面,一个页面的数据远远不够。大家不妨点进链接看看,这里涉及到一个常识吧,第一个页面链接是
    http://www.ganji.com/findjob/resume_list.php?city=194&type=1&major=qzjisuanjiwangluo&tag=&intval1=&key=%E5%85%B6%E4%BB%96%E8%81%8C%E4%BD%8D&open=1&sex=&period=&age=&age_start=&age_end=&edu=&pay=&parttime_pay=&time=
    而下一页是
    http://www.ganji.com/findjob/resume_list.php?city=194&type=1&major=qzjisuanjiwangluo&tag=&intval1=&key=%E5%85%B6%E4%BB%96%E8%81%8C%E4%BD%8D&open=1&sex=&period=&age=&age_start=&age_end=&edu=&pay=&parttime_pay=&time=&page=32
    再下一页呢,对了,最后改为&page=64
    这样的话生成下一个爬取的链接就很简单了,只需要将链接传给parse方法即可
# -*- coding: utf-8 -*-
import scrapy
import requests
from lxml import etree
from resume.items import ResumeItem
import time

class ReSpiderSpider(scrapy.Spider):
    name = 're_spider'
    allowed_domains = ['www.ganji.com']
    start_urls = ['http://www.ganji.com/findjob/resume_list.php?city=194&type=1&major=qzjisuanjiwangluo&tag=&intval1=&key=%E5%85%B6%E4%BB%96%E8%81%8C%E4%BD%8D&open=1&sex=&period=&age=&age_start=&age_end=&edu=&pay=&parttime_pay=&time=']

    def parse(self, response):
        item = ResumeItem()

        item['name'] = response.xpath('//html/body/div[3]/div[2]/dl/dt/a/text()').extract()
        item['sex'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[2]/text()').extract()
        item['age'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[3]/text()').extract()
        item['edu'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[5]/text()').extract()
        item['exp'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[6]/text()').extract()
        item['salary'] = response.xpath('//html/body/div[3]/div[2]/dl/dd[4]/text()').extract()
        yield item
        
        # 提取下一页的url地址
        time.sleep(2)
        start_url = 'http://www.ganji.com/findjob/resume_list.php?city=194&type=1&major=qzjisuanjiwangluo&tag=&intval1=&key=%E5%85%B6%E4%BB%96%E8%81%8C%E4%BD%8D&open=1&sex=&period=&age=&age_start=&age_end=&edu=&pay=&parttime_pay=&time='
        page = 10
        for i in range(1,page):
            next_url = start_url + '&page=' + str(32*i)
                # 发送下一个url地址请求,并指定处理响应的回调函数。
            yield scrapy.Request(
                                        next_url,
                                        callback=self.parse,  # 处理响应的回调函数。
                                        # method="GET",  # 默认GET
                                        # headers={},  # 这里的headers不能存放cookie信息。 默认None
                                        # cookies={},  # 默认None
                                        # meta = {"mydata":item},  # 可以在不同的回调函数中传递数据
                                        # dont_filter=False    # 默认False。 (scrapy默认过滤重复的url)
            )

编写pipelines.py实现存入csv文件

# -*- 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

import pandas as pd
import csv
class ResumePipeline(object):

    def __init__(self):
        self.f = open("E://ProgramData/scrapytest/resume/resume.csv", "w+",newline='')
        self.writer = csv.writer(self.f)
        self.writer.writerow(['姓名', '性别', '年龄', '学历','工作年限','期望薪资'])

#第17个数据是毒瘤,有两条出现‘\xa0’,每次写到17就停止运行,想办法处理掉
    def process_item(self, item, spider):
        i = 0
        while( i<len(item['age']) ):
            try:
                if (i==6 or i==9 or i==16 or i==17):#把毒瘤跳过
                    i = i+1
                else:
                    print('写入序号',i)#检测毒瘤
                    re_list =  [item['name'][i], item['sex'][i], item['age'][i], item['edu'][i],item['exp'][i], item['salary'][i]]
                    self.writer.writerow(re_list)
                    i = i+1
                    print(len(item['name']))
            except:
                continue
        return item
            
    def close_spider(self, spider):#关闭
        self.writer.close()
        self.f.close()

这里小编碰到了一个问题,读取到17个数据就停了,调试半天才发现第17个数据有问题
比如,学历第17个数据是‘\ax0’,运行到此就无法前进。
我直接用暴力检测与暴力跳过的方法抛弃有问题的那一行。
我在想能否用pandas的数据清洗功能来检测异常值,目前还没有搞定,希望优秀的你有好办法的话告知我一声
跳过了异常值

不要忘了配置settings.py

BOT_NAME = 'resume'

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


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

# Obey robots.txt rules
FEED_EXPORT_ENCODING = 'gb18030'#解决csv写入乱码问题
ROBOTSTXT_OBEY = False#False不遵守robots协议
# 配置默认的请求头
header = {
    "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36",
    
}
# 配置使用Pipeline
ITEM_PIPELINES = {
     'resume.pipelines.ResumePipeline': 300,
}

如果不把ROBOTSTXT_OBEY设置为False,是爬取不到数据的,因为scrapy默认遵守robots协议
还有如果写入数据乱码,不妨加一句
FEED_EXPORT_ENCODING = 'gb18030’试试

最后看看爬取效果

名字打码不侵犯隐私
文章到此就结束了,谢谢大家阅读。

原创文章 7 获赞 7 访问量 924

猜你喜欢

转载自blog.csdn.net/weixin_43159092/article/details/105178473
今日推荐