目录
- 1. 数据库建表
- 2. 搭建项目环境
- 创建项目
- 新建爬虫
- 虚拟环境中安装库
 
- 定义数据类型(item.py)
- 爬虫(spiders/csdn.py)
- 管道(pipelines.py)
- 中间件(middlewares.py)
- 项目设置(setting.py)
- 运行测试
- 总结
 
欢迎关注 『scrapy爬虫』 专栏,持续更新中
欢迎关注 『scrapy爬虫』 专栏,持续更新中
看完01-09的内容,实战一下,获取自己文章的访问量 收藏 点赞 数据信息
1. 数据库建表
标题字段2000,因为有些标题和符号确实长~
USE scrapy_csdn;
DROP TABLE IF EXISTS csdn_article;
CREATE TABLE csdn_article (
    `id` INT UNSIGNED AUTO_INCREMENT COMMENT '编号',
    `title` VARCHAR(2000) NOT NULL COMMENT '标题',
	`views` int not null  COMMENT '阅读量',
	`star` int not null  COMMENT '收藏',
	`likes` int not null  COMMENT '点赞数',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='文章信息';

2. 搭建项目环境
创建项目
创建一个名为csdn_scrapy的scrapy项目
scrapy startproject csdn_scrapy

新建爬虫
新建名为csdn的spider
cd csdn_scrapy
scrapy genspider csdn blog.csdn.net

 搭建成功
 
虚拟环境中安装库
import scrapy
import openpyxl
import pymysql
定义数据类型(item.py)
import scrapy
class CsdnScrapyItem(scrapy.Item):
   title = scrapy.Field()
   views = scrapy.Field()
   star = scrapy.Field()
   likes = scrapy.Field()
爬虫(spiders/csdn.py)
import scrapy
from scrapy import Selector,Request
from csdn_scrapy.items import CsdnScrapyItem
class CsdnSpider(scrapy.Spider):
    name = "csdn"
    allowed_domains = ["blog.csdn.net"]
    start_urls = ["http://blog.csdn.net/"]
    def start_requests(self) :
        yield Request(
            url=f'https://blog.csdn.net/u011027547',
            # meta={'proxy':"socket5://127.0.0.1:1086"},#socket5代理
            # meta={'proxy':"http://127.0.0.1:1086"}#购买的商业代理一般是http给一个api接口
            callback=self.parse# 这一行是系统默认带有的,你不写也是默认这样
        )
    def parse(self,response, **kwargs):
        myselector=Selector(text=response.text)
        # 单个文章的选择器
        # #userSkin > div.user-profile-body > div > div.user-profile-body-right > div.navList-box > div.mainContent > div > div > div:nth-child(1) > article
        #拿到了所有文章div组成的list
        list_items=myselector.css("#userSkin > div.user-profile-body > div > div.user-profile-body-right > div.navList-box > div.mainContent > div > div > div> article")
        for list_item in list_items:
            article_item=CsdnScrapyItem()#新建类的对象
            # userSkin > div.user-profile-body > div > div.user-profile-body-right > div.navList-box > div.mainContent > div > div > div:nth-child(1) > article > a > div.list-box-cont > div:nth-child(1) > div.blog-list-box-top > h4
            article_item['title'] = list_item.css("div.blog-list-box-top > h4::text").extract_first()
            #标题会带有这些特殊符号导致异常,所以要进行数据清洗.strip() 是一个字符串方法,用于去除字符串开头和结尾的空格(包括空格、制表符和换行符等)
            article_item['title']=article_item['title'].strip()
            print(article_item['title'])
            # 阅读
            # <span data-v-6fe2b6a7="" class="view-num">385<span data-v-6fe2b6a7="" class="two-px"> 阅读 ·</span></span>
            # 拿到类名是"view-num"的span标签的text文本
            article_item['views']=list_item.css('span[class="view-num"]::text').extract_first()
            print(article_item['views'])
            # 收藏
            # <span data-v-6fe2b6a7="" class="comment-num">21<span data-v-6fe2b6a7="" class="two-px"> 收藏</span></span>
            article_item['star']=list_item.css('span[class="comment-num"]::text').extract_first()
            print(article_item['star'])
            # 点赞
            # <span data-v-6fe2b6a7="" class="give-like-num">11<span data-v-6fe2b6a7="" class="two-px"> 点赞 ·</span></span>
            article_item['likes']=list_item.css('span[class="give-like-num"]::text').extract_first()
            print(article_item['likes'])
            yield article_item#把整理得到的数据给管道
管道(pipelines.py)
对数据进行处理,上传数据到mysql和保存本地excel
import openpyxl
import pymysql
#用于将数据存入mysql的类
class DBPipeline:
    # 初始化
    def __init__(self):
        self.conn=pymysql.connect(host='127.0.0.1',port=3306,
                                  user='root',passwd='123456',database='scrapy_csdn',charset='utf8mb4')
        self.cursor=self.conn.cursor()
        self.data=[]#准备一个存放数据的容器
    # 开始爬虫时候要进行的操作
    def open_spider(self, spider):
        pass
    # 处理爬取到的数据并进行后续处理
    def process_item(self, item, spider):
        title=item.get('title',0)
        views=item.get('views',0)#如果没有获取到评价默认0 因为我们数据是 int
        star=item.get('star',0)#如果没有获取到评价默认0 因为我们数据是 int
        likes=item.get('likes',0)#如果没有获取到评价默认0 因为我们数据是 int
        self.data.append((title,views,star,likes)) #将得到的一行的电影相关数据放入列表
        if len(self.data)>=5:
            self._write_to_db()
        return item #为什么是return? 我们要让这个管道先,return会把item数据传递给下一个管道用于保存excel的
    def _write_to_db(self):
        # execute->改为了 executemany  支持多条数据批量传入数据库
        self.cursor.executemany(
            'insert into csdn_article(title,views,star,likes) values (%s,%s,%s,%s)', self.data
        )
        self.conn.commit()  # 把数据缓冲区的数据提交到数据库
        self.data.clear()  # 每次添加后清空data 避免重复添加数据
    # 关闭爬虫时候要进行的操作
    def close_spider(self, spider):
        if len(self.data) >= 0:#如果还有残留的数据,但是因为不满100条没有传到数据库也要做好处理
            self._write_to_db()
        self.conn.close()
# 用于将数据存入excel的类
class CsdnScrapyPipeline:
    # 初始化我们的excel文件
    def __init__(self):
        self.wb=openpyxl.Workbook()
        self.ws=self.wb.active #拿到默认的被激活的工作表
        self.ws.title="文章信息" #工作表的名字
        self.ws.append(("文章标题","阅读量","收藏量",'点赞量')) #增加表头
    # 开始爬虫时候要进行的操作
    def open_spider(self,spider):
        pass
    # 关闭爬虫时候要进行的操作
    def close_spider(self,spider):
        #保存Excel文件
        self.wb.save("文章信息.xlsx")
        #关闭工作簿(Workbook)和工作表(Worksheet)
        self.wb.close()
    # 处理爬取到的数据 item是我们前面yeild返回的数据
    def process_item(self, item, spider):
        title=item.get('title',0)
        views=item.get('views',0)#如果没有获取到评价默认0 因为我们数据是 int
        star=item.get('star',0)#如果没有获取到评价默认0 因为我们数据是 int
        likes=item.get('likes',0)#如果没有获取到评价默认0 因为我们数据是 int
        self.ws.append((title,views,star,likes))#将得到的数据一行写入excel,注意这里一行是一个元组
        return item
中间件(middlewares.py)
载入cookie,配置代理等等(这里没用代理)
from scrapy import signals
# useful for handling different item types with a single interface
from itemadapter import is_item, ItemAdapter
def get_cookies_dict():
    # cookie字符串转为字典并返回
    cookies_str=''
    cookies_dict={}
    for item in cookies_str.split('; '):# 用 "; "作为分隔符,分割字符串得到列表,比如说列表第一项 ll="118174
        key,vlaue=item.split('=',maxsplit=1)# 用 "="作为分隔符,分割"ll="118174",得到的key和value分别是 li 和 118174
        cookies_dict[key]=vlaue
    return cookies_dict
COOKIES_DICT=get_cookies_dict #全局变量cookie字典
class CsdnScrapySpiderMiddleware:
    # 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, 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 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 CsdnScrapyDownloaderMiddleware:
    @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):
        # request.meta={'proxy':"socket5://127.0.0.1:1086"}#在中间件中请求前拦截请求 添加代理
        request.cookie=COOKIES_DICT #设置cookie
        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)
项目设置(setting.py)
基本的日志,随机等待延时,编码,请求头,并发数量,配置启用管道和中间件.
BOT_NAME = "csdn_scrapy"
SPIDER_MODULES = ["csdn_scrapy.spiders"]
NEWSPIDER_MODULE = "csdn_scrapy.spiders"
# USER_AGENT = "myscrapy (+http://www.yourdomain.com)"#告诉网站 我是爬虫,马上被枪毙~
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
# 是否遵守爬虫协议
ROBOTSTXT_OBEY = True
#设置 Scrapy 引擎同时处理的并发请求数量。 少设置一点不要给网站太大压力! (default: 16)
CONCURRENT_REQUESTS = 8
# 随机下载延迟
RANDOMIZE_DOWNLOAD_DELAY = True
#随机延时
DOWNLOAD_DELAY = 3
#配置日志
LOG_ENABLED = True #开启日志
LOG_LEVEL = 'DEBUG'#设置日志级别。例如,要将日志级别设置为输出所有信息,可以这样配置:通过将日志级别设置为 DEBUG,你可以获取爬虫程序执行过程中的所有详细信息,包括请求、响应、数据处理等各个环节的日志输出。当然,如果你只想获取部分信息,比如只关注警告和错误信息,也可以将日志级别设置为 WARNING 或 ERROR。在运行爬虫时,Scrapy 默认会将日志输出到控制台。如果你希望将日志保存到文件中,还可以设置 LOG_FILE 配置选项,例如:
LOG_FILE = None#设置日志none
# LOG_FILE = 'scrapy.log'#设置日志文件名字 上述配置会将日志输出到名为 scrapy.log 的文件中。
FEED_EXPORT_ENCODING = "utf-8"#通用编码
FEED_EXPORT_ENCODING = "gbk"#中文编码
FEED_OVERWRITE = True # 是否覆盖上次的数据,如果为false每次都是默认的在上次的csv文件后继续写入新的数据
# 配置数据管道
ITEM_PIPELINES = {
    'csdn_scrapy.pipelines.DBPipeline': 200, #数据库管道
    "csdn_scrapy.pipelines.CsdnScrapyPipeline": 300, #数字越小先执行,后期可以有多个管道
    # '你的项目名.pipelines.刚刚管道的类名': 权重, #权重越小先执行,后期可以有多个管道
}
# 配置下载中间件
DOWNLOADER_MIDDLEWARES = {
   "csdn_scrapy.middlewares.CsdnScrapyDownloaderMiddleware": 543,
}
# # 配置爬虫中间件
#SPIDER_MIDDLEWARES = {
#    "csdn_scrapy.middlewares.CsdnScrapySpiderMiddleware": 543,
#}
REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"
运行测试
虚拟环境中运行~
scrapy crawl csdn
- 成功保存到数据库
如果没有进行数据清洗使用.strip()处理标题,你会看到下图,而且excel的标题会异常
 
 经过数据清洗后标题前后没有空白的换行符和空格了
 
- 成功保存到excel
  
总结
大家喜欢的话,给个👍,点个关注!给大家分享更多计算机专业学生的求学之路!
版权声明:
发现你走远了@mzh原创作品,转载必须标注原文链接
Copyright 2024 mzh
Crated:2024-3-1
欢迎关注 『scrapy爬虫』 专栏,持续更新中
欢迎关注 『scrapy爬虫』 专栏,持续更新中
『未完待续』



















