Scrapy爬虫项目学习

一、创建scrapy项目

1.安装scrapy环境

pip install -i 镜像网站 scrapy

2.在指令目录创建scrapy工程

scrapy startproject 项目名
image.png

二、创建爬虫文件

Scrapy爬虫具有一下特性: Scrapy的方法,负责将爬取的页面数据包装成response
Scrapy方法会为start_url中的所有地址执行一遍
Scrapy具有网页追踪机制,当我们在parse提供一个yield的请求后将会不断请求传入的url,并执行回调函数进行解析

一.在spider目录下创建一个爬虫文件(这里scrapy项目会自动的从spiders文件夹下寻找爬虫文件)---jobbole.py
二.在爬虫文件下创建类,继承scrapy.spider

1.指定name,指定爬虫程序名称,在启动scrapy时需要用到
2.指定allowed_domains(非必要),指定爬去url的域名,如果不在该域名下的url将被过滤不去爬取
3.start_urls爬取的起始url
4.一定要把ROBOTSTXT_OBEY 设置成false,否则会查询每一个网站是否同意robots协议。如果网站设置的false,那么将不爬去
5.parse函数负责解析数据,在这里负责解析,在最后调用yield返回Request对象,Request的callback执行parse,这样就可以不断反复爬取。

image.png

三。定义一个Item类,继承自scrapy.item,负责保存数据
四。在piplines文件下创建一个piplines。提供process_item方法,负责接收parse传递过来的item
五。在settings中的ITEM_PIPLELINES字典中指定启用的pipelines。

在爬虫类的parse方法中,如果使用yield返回了item,那数据将交给piplines处理,piplines这个类负责保存数据。

setttings.png

1。保存Json数据的pipline
使用scrapy提供的export即可(scrapy提供了多种export)

from scrapy.exporters import JsonItemExporter
class JobJsonExporter(object):
    def __init__(self):
        self.file = codecs.open('job_exporter.json', 'wb')
        self.exporter = JsonItemExporter(file=self.file, encoding='utf-8', ensure_ascii=False)
        self.exporter.start_exporting()

    def process_item(self, item, spider):
        # 传递数据给exporter
        self.exporter.export_item(item)
        return item

    def spider_closed(self, spider):
        self.exporter.finish_exporting()
        self.file.close()

2.保存数据到数据库
scrapy提供了twisted类来完成异步数据库的读写操作,需要引入twisted和pymysql

from twisted.enterprise import adbapi
import pymysql.cursors

class JobMySqlPipline(object):
    def __init__(self,dbPool):
        self.dbPool=dbPool

    ##这个方法会在pipline初始化的时候调用
    @classmethod
    def from_settings(cls, settings):
        host = settings["MY_HOST"]
        port = settings["MY_PORT"]
        account = settings["MY_ACCOUNT"]
        password = settings["MY_PASSWORD"]
        database = settings["MY_DATABASE"]
        # 要跟使用的mysql框架对应
        dbParams = dict(host=host, db=database, user=account, password=password, port=port,
                        charset='utf8', use_unicode=True)
        print("from settings : " + host + " password : " + password)
        #将数据库操作编程异步操作,这里pymysql代表使用的数据库
        dbPool = adbapi.ConnectionPool("pymysql", **dbParams)
        return cls(dbPool)

    def process_item(self, item, spider):
        # 传递数据给exporter
        # 使用twisted和mysql将数据库插入编程异步操作,需要指定插入方法回调
        query= self.dbPool.runInteraction(self.do_insert,item)
        #添加异步错误处理操作
        query.addErrback(self.handleError,item,spider)
        return item
    #执行插入方法回调
    def do_insert(self,cursor,item):
        sql = """
                    insert into article_spider(title,url,front_img_path,praise_nums)
                  VALUES (%s,%s,%s,%s)
                   """
        cursor.execute(sql, (item['title'], item['url'], item['front_img_url'], item['praise_nums'],))
        #不再需要commit操作,这个操作自动完成
        #self.conn.commit()
        ###处理异常毁掉
    def handleError(self,failuer,item,spider):
        print(failuer)

三、调试scrapy

创建一个入口函数文件,如上图的main.py.
1.使用sys.path.append方法将main.py加入到环境变量中
2.使用execute函数,执行脚本,这里第三个参数代表执行的爬虫文件,一定要和爬虫文件中的Name对应上

import sys
import os
from scrapy.cmdline import execute
##output:/Users/apple/Desktop/workspace/pythonwork/ArticleSpider
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
execute(['scrapy',"crawl","jobbole"])

四、Item优化

使用Itemloader来封装数据,使用ItemLoader封装数据后,赋予的每一个字段值都是数组
1.引入Itemloader

from scrapy.loader import ItemLoader

2.使用add方法解析数据
创建ItemLoader对象,传入reponse和item类型对象

add_css 负责解析css谁
add_xpath 解析xpath数据
add_value 直接对字赋值
load_item:生成item

        itemLoader=ItemLoader(item=JoBBoleArticleItem(),response=response)
        itemLoader.add_css("title",".entry-header h1::text")
        itemLoader.add_css("create_date","p.entry-meta-hide-on-mobile::text")
        itemLoader.add_value("front_img_url",[front_image_url])
        itemLoader.add_value("url",response.url)
        itemLoader.add_css("praise_nums",".vote-post-up h10::text")
        itemLoader.add_css("commment_nums","a[href='#article-comment'] span::text")
        #解析生成item
        article_item=itemLoader.load_item()

获取到的值:title,url等拿到的都是一个数组


image.png

2.通过processor预处理拿到的数据
引入MapCompse这个processor,可以对字段执行一些函数

from scrapy.loader.processors import MapCompose,TakeFirst

通过scrapy.Field方法指定input_processor为MapCompose,这里表示在输入预处理函数为MapCompose,而MapCompose又接收多个函数,表示拿到的数据依次执行传入的方法(例如title,依次执行了匿名函数,addTitle方法)

def addTtitle(value):
    return value+'-guo'
"""
解析时间
"""
def parseData(data):
  try:
      create_date = datetime.datetime.strptime(data, "%Y/%m/%d").date()
  except Exception as e:
      create_date = datetime.datetime.now().date()
  return create_date

class JoBBoleArticleItem(scrapy.Item):
    """
    标题
    """
    title = scrapy.Field(
        #MapCompose需要传入一个回调函数,可以对取到的值做预处理
        #可以接收多个方法
        input_processor=MapCompose(lambda x:x+"-spider",addTtitle)
    )
    create_date = scrapy.Field(input_processor=MapCompose(parseData))

3.解决字段值为数组问题

1.通过引入TakeFirst这个Processors,它可以自动的取出数组中第一个值作为字段值。
2.自定义ItemLoader
3.指定Item的默认输出类型为TakeFirst

class FirstItemLoader(ItemLoader):
    default_output_processor = TakeFirst()

4.使用自定义ItemLoader替代ItemLoader

itemLoader=FirstItemLoader(item=JoBBoleArticleItem(),response=response)
itemLoader.add_css("title",".entry-header h1::text")     

你可能感兴趣的:(Scrapy爬虫项目学习)