首页 > 其他分享 >爬虫_05days ↑

爬虫_05days ↑

时间:2024-02-23 15:26:22浏览次数:27  
标签:url 爬虫 item scrapy article extract 05days desc

scrapy 架构介绍

# scrapy:爬虫框架---》使用scrapy创建爬虫项目
# pip install scrapy
# 创建scrapy项目
scrapy startproject 项目名

# 架构
spiders:爬虫,主要是咱们写代码的地方---》设置起始爬取的地址--》解析数据
engine:引擎,大总管,控制数据的整体流动
scheduler:调度器,待爬取的地址,排队,去重
middleware:中间件:下载中间件,爬虫中间件
downloader:下载器,真正下载
pipline:管道,持久化,保存,文件,mysql

 

# 引擎(EGINE)
引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。

# 调度器(SCHEDULER)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址

# 下载器(DOWLOADER)
用于下载网页内容, 并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的

# 爬虫(SPIDERS)
SPIDERS是开发人员自定义的类,用来解析responses,并且提取items,或者发送新的请求

# 项目管道(ITEM PIPLINES)
在items被提取后负责处理它们,主要包括清理、验证、持久化(比如存到数据库)等操作

# 下载器中间件(Downloader Middlewares)

位于Scrapy引擎和下载器之间,主要用来处理从EGINE传到DOWLOADER的请求request,已经从DOWNLOADER传到EGINE的响应response,你可用该中间件做以下几件事

# 爬虫中间件(Spider Middlewares)
位于EGINE和SPIDERS之间,主要工作是处理SPIDERS的输入(即responses)和输出(即requests)

scrapy 目录结构

myfirstscrapy # 项目名字
-myfirstscrapy # 包
-__init__.py
-spiders # 包 放爬虫,可能会有很多爬虫
-__init__.py
-cnblogs.py # 爬虫文件--》一个爬虫就是一个文件,可以写多个

-items.py # 放一个个类---》类似于django 的models--》模型类
-middlewares.py # 中间件,下载,爬虫中间件
-pipelines.py # 持久化,保存mysql,需要写的位置
-settings.py #配置文件
-scrapy.cfg # 上线会用



# 以后咱们如果写爬虫,写解析,就写 spiders 下的某个py文件 咱么写的最多的
# 以后配置都写在settings 中
# 以后想写中间件:middlewares
# 以后想做持久化:pipelines,items

scrapy爬取和解析

# 1 创建项目:scrapy startproject 项目名
# 2 创建爬虫:scrapy genspider 爬虫名 爬取的地址
scrapy gensipder cnblogs www.cnblogs.com
# 3 运行爬虫
运行cnblgos爬虫---》对首页进行爬取
scrapy crawl 爬虫名字
scrapy crawl cnblogs

scrapy crawl cnblogs --nolog


# 4 快速运行,不用命令
项目根路径新建 run.py,写入如下代码,以后右键运行run.py 即可
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', 'cnblogs', '--nolog'])



# 5 解析数据---》提供了解析库--》css和xpath
1 response对象有css方法和xpath方法
  -css中写css选择器 response.css('')
  -xpath中写xpath选择 response.xpath('')
2 重点1:
-xpath取文本内容
  './/a[contains(@class,"link-title")]/text()'
-xpath取属性
  './/a[contains(@class,"link-title")]/@href'
-css取文本
  'a.link-title::text'
-css取属性
  'img.image-scale::attr(src)'
3 重点2:
  .extract_first() 取一个
  .extract() 取所有

css解析

    def parse(self, response):  # css解析
        # response 就是爬完后的对象
        # print(response.text)
        # 使用css解析
        article_list = response.css('article.post-item')
        for article in article_list:
            # 标题
            title = article.css('a.post-item-title::text').extract_first()
            # 摘要 取出所有,单独处理一下
            desc = article.css('p.post-item-summary::text').extract()
            real_desc = desc[0].replace('\n', '').replace(' ', '')
            if not real_desc:
                real_desc = desc[1].replace('\n', '').replace(' ', '')
            # print(real_desc)
            # 作者:author
            author = article.css('footer.post-item-foot>a>span::text').extract_first()
            # print(author)
            # 头像
            image_url = article.css('img.avatar::attr(src)').extract_first()
            # print(image_url)
            # 发布日期
            date = article.css('span.post-meta-item>span::text').extract_first()
            # print(date)

            # 文章地址
            url = article.css('a.post-item-title::attr(href)').extract_first()

            print('''
            文章名:%s
            文章摘要:%s
            文章作者:%s
            作者头像:%s
            文章日期:%s
            文章地址:%s
            ''' % (title, real_desc, author, image_url, date, url))

xpath

    def parse(self, response):  # xpath解析
        article_list = response.xpath('//article[@class="post-item"]')
        for article in article_list:
            # 标题
            title = article.xpath('.//a[@class="post-item-title"]/text()').extract_first()

            # 摘要 取出所有,单独处理一下
            desc = article.xpath('.//p[@class="post-item-summary"]/text()').extract()
            real_desc = desc[0].replace('\n', '').replace(' ', '')
            if not real_desc:
                real_desc = desc[1].replace('\n', '').replace(' ', '')
            # print(real_desc)
            # 作者:author
            # author = article.css('footer.post-item-foot>a>span::text').extract_first()
            author = article.xpath('.//footer[@class="post-item-foot"]/a/span/text()').extract_first()
            # print(author)
            # 头像
            # image_url = article.css('img.avatar::attr(src)').extract_first()
            image_url = article.xpath('.//img[@class="avatar"]/@src').extract_first()
            # print(image_url)
            # 发布日期
            # date = article.css('span.post-meta-item>span::text').extract_first()
            date = article.xpath('.//span[@class="post-meta-item"]/span/text()').extract_first()
            # print(date)

            # 文章地址
            # url = article.css('a.post-item-title::attr(href)').extract_first()
            url = article.xpath('.//a[@class="post-item-title"]/@href').extract_first()

            print('''
              文章名:%s
              文章摘要:%s
              文章作者:%s
              作者头像:%s
              文章日期:%s
              文章地址:%s
              ''' % (title, real_desc, author, image_url, date, url))

 

整站爬取cnblogs

 parse

   def parse(self, response):  # xpath解析
        article_list = response.xpath('//article[@class="post-item"]')
        for article in article_list:
            # 标题
            title = article.xpath('.//a[@class="post-item-title"]/text()').extract_first()

            # 摘要 取出所有,单独处理一下
            desc = article.xpath('.//p[@class="post-item-summary"]/text()').extract()
            real_desc = desc[0].replace('\n', '').replace(' ', '')
            if not real_desc:
                real_desc = desc[1].replace('\n', '').replace(' ', '')
            # print(real_desc)
            # 作者:author
            # author = article.css('footer.post-item-foot>a>span::text').extract_first()
            author = article.xpath('.//footer[@class="post-item-foot"]/a/span/text()').extract_first()
            # print(author)
            # 头像
            # image_url = article.css('img.avatar::attr(src)').extract_first()
            image_url = article.xpath('.//img[@class="avatar"]/@src').extract_first()
            # print(image_url)
            # 发布日期
            # date = article.css('span.post-meta-item>span::text').extract_first()
            date = article.xpath('.//span[@class="post-meta-item"]/span/text()').extract_first()
            # print(date)

            # 文章地址
            # url = article.css('a.post-item-title::attr(href)').extract_first()
            url = article.xpath('.//a[@class="post-item-title"]/@href').extract_first()

            # print('''
            #   文章名:%s
            #   文章摘要:%s
            #   文章作者:%s
            #   作者头像:%s
            #   文章日期:%s
            #   文章地址:%s
            #   ''' % (title, real_desc, author, image_url, date, url))

            # 1 保存数据
            # 2 继续爬取---》下一页   文章详情

            # 继续爬取文章详情--->解析和首页解析是不一样的
            yield Request(url=url, callback=self.parse_detail)

        # 继续爬下一页
        # yield Request(url=url, callback=self.parse) #callback可以不写
        # 解析下一页地址 之css
        # next_url = 'https://www.cnblogs.com' + response.css('div.pager a:last-child::attr(href)').extract_first()
        # 解析下一页地址 之xpath
        next_url = 'https://www.cnblogs.com' + response.xpath('//div[@class="pager"]/a[last()]/@href').extract_first()
        print(next_url)
        yield Request(url=next_url, callback=self.parse)

parse_detail

def parse_detail(self, response):
    print(len(response.text))
    # 解析出文章详情--》存html
    # content=str(response.css('#cnblogs_post_body').extract_first())
    # content=str(response.xpath('//div[id="cnblogs_post_body"]').extract_first())
    # content=str(response.xpath('//div[contains(@class,"blogpost-body")]').extract_first())
    content=str(response.xpath('//div[@id="cnblogs_post_body"]').extract_first()) # 通过id拿不到
    print(content)

持久化

# 能实现整站爬取
    1 首页---下一页
    2 详情页
    
# 目标是要保存数据
    -parse中解析出来文章的一部分内容:标题,作者,摘要。。。缺了文章详情
    -parse_detail中有:文章详情-
    -刚刚爬取的某片文章 跟 文章详情,对应不上,咱们没法合道一起
    
    
    
# 数据传递---》上一个请求中携带数据,传递给下一个响应

数据传递--上一个请求中携带数据,传递给下一个响应

#  上一个解析中,放到request中
item = MyfirstscrapyItem(title=title, real_desc=real_desc, author=author, image_url=image_url, date=date, url=url)
yield Request(url=url, callback=self.parse_detail, meta={'item': item})

# 下一个解析中,取出来
item = response.meta.get('item')

持久化数据

 在items中新建类

class MyfirstscrapyItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
    real_desc = scrapy.Field()
    date = scrapy.Field()
    image_url = scrapy.Field()
    url = scrapy.Field()
    # ------文章详情-----
    content = scrapy.Field()

在解析中,得到item对象,并且yield

# 第一个解析
item = MyfirstscrapyItem(title=title, real_desc=real_desc, author=author, image_url=image_url, date=date,url=url)
# 第二个解析
item['content'] = content
# yield
yield item

配置文件

ITEM_PIPELINES = {
   "myfirstscrapy.pipelines.MyfirstscrapyFilePipeline": 300,
   "myfirstscrapy.pipelines.MyfirstscrapyMysqlPipeline": 100,
}

pipelines.py

#### 注意爬虫开启和关闭
from itemadapter import ItemAdapter
import pymysql

class MyfirstscrapyFilePipeline:
    # 每条记录,都会走这里,如果打开mysql和关闭,都在这个方法中得话
    # 我们应该在爬虫开启的时候,打开mysql链接,爬虫关闭的时候,关闭链接
    def open_spider(self, spider):
        print('开了')
        # 打开文件
        self.f = open('cnblogs.txt', 'wt', encoding='utf-8')

    # 先用文件演示---》
    def process_item(self, item, spider):
        self.f.write(item['title'] + '\n')
        print('=======', item['title'])
        self.f.flush()
        return item

    def close_spider(self, spider):
        print('关了')
        # 关闭文件
        self.f.close()


class MyfirstscrapyMysqlPipeline:
    def open_spider(self, spider):
        self.conn = pymysql.connect(
            user='root',
            password="1234",
            host='127.0.0.1',
            database='cnblogs',
            port=3306,
        )
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        self.cursor.execute(
            'INSERT INTO article (title,author,url,img_url,`date`,real_desc,content)VALUES(%s,%s,%s,%s,%s,%s,%s)',
            args=[item['title'], item['author'], item['url'], item['image_url'], item['date'], item['real_desc'],
                  item['content']])
        self.conn.commit()
        return item

    def close_spider(self, spider):
        self.cursor.close()
        self.conn.close()

配置文件

#### 基础配置
# 项目名
BOT_NAME = "scrapy_demo"
# 爬虫所在路径
SPIDER_MODULES = ["scrapy_demo.spiders"]
NEWSPIDER_MODULE = "scrapy_demo.spiders"

# 记住  日志级别
LOG_LEVEL='ERROR'


# 请求头中的  USER_AGENT
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"

# 是否遵循爬虫协议
ROBOTSTXT_OBEY = False



# 默认请求头
#DEFAULT_REQUEST_HEADERS = {
#    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
#    "Accept-Language": "en",
#}

#爬虫中间件
#SPIDER_MIDDLEWARES = {
#    "scrapy_demo.middlewares.ScrapyDemoSpiderMiddleware": 543,
#}

# 下载中间件
#DOWNLOADER_MIDDLEWARES = {
#    "scrapy_demo.middlewares.ScrapyDemoDownloaderMiddleware": 543,
#}



# 持久化相关
#ITEM_PIPELINES = {
#    "scrapy_demo.pipelines.ScrapyDemoPipeline": 300,
#}



### 高级配置(提高爬取效率)
#1 增加并发:默认16
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改
CONCURRENT_REQUESTS = 100
值为100,并发设置成了为100

#2 提高日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:
LOG_LEVEL = 'INFO'


# 3 禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:
COOKIES_ENABLED = False

# 4 禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:
RETRY_ENABLED = False

# 5 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:
DOWNLOAD_TIMEOUT = 10 超时时间为10s

 

标签:url,爬虫,item,scrapy,article,extract,05days,desc
From: https://www.cnblogs.com/wzh366/p/18029601

相关文章

  • 爬虫_04days
    自动登录cnblogs--获取cookieimporttimeimportjsonfromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromselenium.webdriver.chrome.optionsimportOptions#####绕过浏览器检测到自动化软件控制options=Options()options.add_argum......
  • 爬虫简介
    爬虫分类:  通用爬虫:抓取系统重要组成部分,抓取的是一个整张页面的数据  聚焦爬虫:是建立在通用爬虫的基础之上。抓取的是页面中特定的局部内容  增量式爬虫:检测网站中数据更新的情况,指挥抓取网站中最新更新出来的数据爬虫的矛与盾:反爬机制  门户网站,可以通过制定相应......
  • 爬虫03_days
    selenium介绍#1由于requests不能执行js---》逐个分析ajax请求--》模拟发送获取数据 -使用requests爬取的数据很大概率跟在浏览器中看到的不一样-requests不能执行js#2seleniumselenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaS......
  • Scrapy爬虫框架
    一、安装Scrapypipinstallscrapy二、创建scrapy项目scrapystartprojectmy_spider三,创建爬虫文件scrapygenspiderexampleexample.com#example文件名称#example.com爬取网站地址#如:scrapygenspiderbaidubaidu.com出现下图就创建成功 四、运行刚才......
  • python 爬虫模板
    前言在我们写爬虫的时候,一般想要的数据都在详情页里面,一般代码进入详情页参数,需要首页里面寻找,所以爬这样的网站,需要定义一个模板我的模板如下: importrandomimporttimeimportrequestsfromauctionimportlogtoolfromauction.BaseCrawlerimportBaseCrawlercla......
  • python实战:用requests+做爬虫
    一,安装requests1,用pip安装(venv)liuhongdi@192news%pip3installrequests2,查看所安装库的版本:(venv)liuhongdi@192news%pip3showrequestsName:requestsVersion:2.31.0Summary:PythonHTTPforHumans.Home-page:https://requests.readthedocs.ioAu......
  • 爬虫_02days
    免费代理池搭建#代理有免费和收费代理#代理有http代理和https代理#匿名度 -高匿:隐藏访问者ip-透明:服务端能拿到访问者ip-作为后端,如何拿到使用代理人的ip -请求头中:x-forword-for-如果一个HTTP请求到达服务器之前,经过了三个代理Proxy1、Proxy2、Proxy3......
  • 爬虫——day01
    爬虫介绍爬虫是什么? -通过编程技术---》把互联网中的数据---》获取到---》数据清洗---》存到库中python:request,selenium---》app,小程序,网站---》xpaht,lxml---》mysql,redis,文件,excel,mongodb-通过编程语言---》模拟发送http请求---》获取数据---》解析--》入库......
  • 【60行代码解决】2024年最新版python爬虫有道翻译js逆向
    一、表单参数sign加密sign:c0f36866a9c650144ed5bac4eba532a7这种32位一般是MD5加密1.搜索sign:2.点击去分别在每个**sign:某某某**处打上断点结果在这个断点断住了3.原代码constu="fanyideskweb",d="webfanyi"functionj(e){returnc.a.createHash......
  • 第 8章 Python 爬虫框架 Scrapy(下)
    第8章Python爬虫框架Scrapy(下)8.1Scrapy对接Selenium有一种反爬虫策略就是通过JS动态加载数据,应对这种策略的两种方法如下:分析Ajax请求,找出请求接口的相关规则,直接去请求接口获取数据。使用Selenium模拟浏览器渲染后抓取页面内容。8.1.1如何对接单独使用Sc......