爬虫框架-scrapy的使用
Scrapy
- Scrapy是纯python实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架。
- Scrapy使用了Twisted异步网络框架来处理网络通讯,可以加快我们的下载速度,并且包含了各种中间件接口,可以灵活的完成各种需求
1、安装
sudo pip3 install scrapy
2、认识scrapy框架
2.1 scrapy架构图
Scrapy Engine(引擎)
: 负责Spider
、ItemPipeline
、Downloader
、Scheduler
中间的通讯,信号、数据传递等。Scheduler(调度器)
: 它负责接受引擎
发送过来的Request请求,并按照一定的方式进行整理排列,入队列,当引擎
需要时,交还给引擎
。Downloader(下载器)
:负责下载Scrapy Engine(引擎)
发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎)
,由引擎
交给Spider
来处理Spider(爬虫)
:它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎
,再次进入Scheduler(调度器)
Item Pipeline(管道)
:它负责处理Spider
中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方.Downloader Middlewares(下载中间件)
:你可以当作是一个可以自定义扩展下载功能的组件Spider Middlewares(Spider中间件)
:可以理解为是一个可以自定扩展和操作引擎
和Spider
中间通信
的功能组件(比如进入Spider
的Responses和从Spider
出去的Requests)2.2 Scrapy运行的大体流程:
1.引擎从spider拿到第一个需要处理的URL,并将request请求交给调度器。
2.调度器拿到request请求后,按照一定的方式进行整理排列,入队列,并将处理好的request请求返回给引擎。
3.引擎通知下载器,按照下载中间件的设置去下载这个request请求。
4.下载器下载request请求,并将获取到的response按照下载中间件进行处理,然后后交还给引擎
,由引擎
交给spider
来处理。对于下载失败的request,引擎会通知调度器进行记录,待会重新下载。
5.spider拿到response,并调用回调函数(默认调用parse函数)去进行处理,并将提取到的Item数据和需要跟进的URL交给引擎。
6.引擎将item数据交给管道进行处理,将需要跟进的URL交给调度器,然后开始循环,直到调度器中不存在任何request,整个程序才会终止。
2.3 制作scrapy爬虫步骤:
1.创建项目:通过(scrapy startproject 项目名)来创建一个项目
2.明确目标:编写items.py文件,定义提取的Item
3.制作爬虫:编写spiders/xx.py文件,爬取网站并提取Item
4.存储内容:编写pipelines.py文件,设计管道来存储提取到的Item(即数据)
3、入门教程
3.1 创建项目
- 在开始爬虫之前,第一步需要创建一个项目。先进入打算存储代码的目录,运行以下命令:
scrapy startproject myProject
- 其中myProject为项目名,运行上述命令后,在当前目录下会创建一个myProject目录,该目录包含以下内容:
.
├── myProject
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ └── __init__.py
└── scrapy.cfg
- 在开始爬虫之前,第一步需要创建一个项目。先进入打算存储代码的目录,运行以下命令:
scrapy.cfg:项目的配置文件
myProject/items.py:项目中的目标文件
myProject/middlewares.py:项目中的中间件文件
myProject/pipelines.py:项目中的管道文件
myProject/settings.py:项目中的设置文件
myProject/spiders:放置spider代码的目录
3.2 明确目标(定义Item)
- 我们打算抓取网站http://www.itcast.cn/channel/teacher.shtml#ajavaee里所有老师的姓名、职称、入职时间和个人简介:
- 首先打开myProject/items.py文件
- Item是保存爬取到的数据的容器,其使用方法和python字典类似
- 创建一个scrapy.Item 类, 并且定义类型为 scrapy.Field的类属性来定义一个Item(类似于ORM的映射关系)
- 创建一个MyprojectItem 类,和构建item模型(model)
import scrapy class MyprojectItem(scrapy.Item):
name = scrapy.Field()
title = scrapy.Field()
hiredate = scrapy.Field()
profile = scrapy.Field()
3.3 制作爬虫
- 在项目根目录下输入以下命令,可以在myProject/spiders目录下创建一个名为itcast的爬虫(itcast.py),并且指定爬虫作用域的范围itcast.cn:
scrapy genspider itcast itcast.cn
- 打开itcast.py,默认添上了以下内容:
import scrapy class ItcastSpider(scrapy.Spider):
name = 'itcast'
allowed_domains = ['itcast.cn']
start_urls = ['http://itcast.cn/'] def parse(self, response):
pass 要建立一个Spider, 你必须用scrapy.Spider类创建一个子类,并确定了3个强制的属性和1个方法。
name:
这个爬虫的识别名称,必须是唯一的allow_domains:
爬虫的约束区域,规定爬虫只爬取这个域名下的网页,不存在的URL会被忽略。start_urls:
爬取的URL列表。因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始URL返回的数据中提取。parse(self, response):
Request对象默认的回调解析方法。每个初始URL完成下载后将被调用,调用的时候传入从每一个URL传回的Response对象来作为唯一参数,该方法负责解析返回的数据(response.body),提取数据(生成item)以及生成需要进一步处理的URL的Request对象
- 修改start_urls为第一个需要爬取的URL:
start_urls = ['http://www.itcast.cn/channel/teacher.shtml#ajavaee']
- 修改parse方法提取Item:
def parse(self, response):
for teacher in response.xpath("//ul[@class='clears']/li/div[@class='main_mask']"):
#将提取到到的数据封装到一个MyprojectItem对象中
item = MyprojectItem()
#利用xpath返回该表达式所对应的所有节点的selector list列表
#调用extract方法序列化每个节点为Unicode字符串并返回list
name = teacher.xpath('h2/text()').extract()[0]
title = teacher.xpath('h2/span/text()').extract()[0]
hiredate = teacher.xpath('h3/text()').extract()[0].split(':')[-1]
profile = teacher.xpath('p/text()').extract()[0]
item['name'] = name
item['title'] = title
item['hiredate'] = hiredate
item['profile'] = profile
# 使用yield将获取的数据交给pipelines,如果使用return,则数据不会经过pipelines
yield item
- 在项目根目录下输入以下命令,可以在myProject/spiders目录下创建一个名为itcast的爬虫(itcast.py),并且指定爬虫作用域的范围itcast.cn:
3.4 存储内容
Feed输出
- 如果仅仅想要保存item,可以不需要实现任何的pipeline,而是使用自带的Feed输出(Feed export)。主要有以下4种方式,通过-o指定输出文件格式:
# json格式,默认为Unicode编码
scrapy crawl itcast -o itcast.json
# json lines格式,默认为Unicode编码
scrapy crawl itcast -o itcast.jsonl
#csv 逗号表达式,可用Excel打开
scrapy crawl itcast -o itcast.csv
# xml格式
scrapy crawl itcast -o itcast.xml执行这些命令后,将会对爬取的数据进行序列化,并生成文件。
- 如果仅仅想要保存item,可以不需要实现任何的pipeline,而是使用自带的Feed输出(Feed export)。主要有以下4种方式,通过-o指定输出文件格式:
编写Item Pipeline(通用):
- 每个Item Pipeline都是实现了简单方法的Python类,他们接收到Item并通过它执行一些行为,同时也决定此Item是丢弃还是被后续pipeline继续处理。
- 每个item pipeline组件必须实现process_item(self,item,spider)方法:
- 这个方法必须返回一个Item (或任何继承类)对象, 或是抛出 DropItem异常。
- 参数是被爬取的item和爬取该item的spider
- spider程序每yield一个item,该方法就会被调用一次
- 同时还可以实现以下方法:
- open_spider(self,spider):开启spider的时候调用,只执行1次
- close_spider(self,spider):关闭spider的时候调用,只执行1次
item写入json文件:
import json
from itemadapter import ItemAdapter class MyprojectPipeline:
def open_spider(self,spider):
'''可选实现,开启spider时调用该方法'''
self.f = open('itcast.json','w') def process_item(self, item, spider):
'''必须实现,被抛弃的item将不会被后续的pipeline组件所处理'''
self.f.write(json.dumps(dict(item),ensure_ascii=False)+'\n')
return item def close_spider(self,spider):
'''可选实现,关闭spider时调用该方法'''
self.f.close()启用Item Pipeline组件
ITEM_PIPELINES = {
'myProject.pipelines.MyprojectPipeline': 300,
}在settings.py文件里添加以上配置(可以取消原有的注释),后面的数字确定了item通过pipeline的顺序,通常定义在0-1000范围内,数值越低,组件的优先级越高
启动爬虫
scrapy crawl itcast
查看当前目录下是否生成了itcast.json文件
4、Scrapy Shell
Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据。
启动scrapy shell
scrapy shell <url>
命令行启动,url是要爬取的网页的地址
常见可用对象response
- response.status:状态码
- response.url:当前页面url
- response.body:响应体(bytes类型)
- response.text:响应文本(str类型)
- response.json():如果响应体的是json,则直接转换成python的dict类型
- response.headers:响应头
- response.selector:返回Selector对象,之后就可以调用xpath和css等方法,也可以简写成response.xpath()和response.css()
selector选择器
Selector有四个基本的方法,最常用的还是xpath:
- xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表
- extract(): 序列化该节点为Unicode字符串并返回list
- css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同 BeautifulSoup4
- re(): 根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表
5、Spider
Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。
- scrapy.Spider是最基本的类,所有编写的爬虫必须继承这个类。
import scrapy class XxSpider(scrapy.Spider):
pass - 主要用到的函数及调用顺序为:
- __init__():初始化爬虫名字和start_urls列表
- start__requests(self):调用make_requests_from_url()生成Requests对象交给Scrapy下载并返回response
- parse(self,response):解析response,并返回Item或Requests(需指定回调函数)。Item传给Item pipline持久化 , 而Requests交由Scrapy下载,并由指定的回调函数处理(默认parse()),一直进行循环,直到处理完所有的数据为止。
- 其他方法
- log(self, message, level=log.DEBUG)
- message:字符串类型,写入的log信息
- level:log等级,有CRITICAL、 ERROR、WARNING、INFO、DEBUG这5种,默认等级为DEBUG
- log(self, message, level=log.DEBUG)
6、CrwalSpider
快速创建CrawlSpider模板:
scrapy genspider -t crawl 爬虫名 爬虫域
- scrapy.spiders.CrwalSpider是编写的爬虫所必须继承的类
from scrapy.spiders import CrawlSpider class XxSpider(CrawlSpider):
passCrawlSpider类继承于Spider类,它定义了一些规则(rule)来提供跟进link的方便的机制,从爬取的网页中获取link并继续爬取的工作更适合。
LinkExtractor
class scrapy.spiders.LinkExtractor
- 每个LinkExtractor对象有唯一的公共方法是 extract_links(),它接收一个Response对象,并返回一个 scrapy.link.Link 对象。根据不同的response调用多次来提取链接
主要参数:
allow:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。
deny:与这个正则表达式(或正则表达式列表)匹配的URL一定不提取。
allow_domains:会被提取的链接的domains。
deny_domains:一定不会被提取链接的domains。
restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。
rules
class scrapy.spiders.Rule
- 在rules中包含一个或多个Rule对象,每个Rule对爬取网站的动作定义了特定操作。如果多个rule匹配了相同的链接,第一个会被使用。
- Rule对象主要参数:
- link_extractor:是一个Link Extractor对象,用于定义需要提取的链接
- callback:从link_extractor中每获取到链接时,该回调函数接受一个response作为其第一个参数。注意:字符串类型,避免使用'parse'
- follow:布尔类型,指定了根据该规则从response提取的链接是否需要跟进。 如果callback为None,follow 默认设置为True ,否则默认为False。
- process_links:指定函数,从link_extractor中获取到链接列表时将会调用该函数,主要用来过滤。
- process_requests:指定函数, 该规则提取到每个request时都会调用该函数,用来过滤request。
CrawSpider爬虫示例
- 以阳光热线问政平台http://wz.sun0769.com/political/index/politicsNewest?id=1为例,爬取投诉帖子的编号、帖子的标题,帖子的处理状态和帖子里的内容。
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from myProject.items import MyprojectItem class SunSpider(CrawlSpider):
name = 'sun'
allowed_domains = ['wz.sun0769.com']
start_urls = ['http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1'] rules = (
Rule(LinkExtractor(allow=r'id=\d+&page=\d+')),#每一页的匹配规则,callback为None,默认跟进
Rule(LinkExtractor(allow=r'politics/index\?id=\d+'), callback='parse_item'),#每个帖子的匹配规则,设置了callback,默认不跟进
) def parse_item(self, response):
item = MyprojectItem()
title = response.xpath('//div[@class="mr-three"]/p[@class="focus-details"]/text()').extract()[0] #帖子标题
status = response.xpath('//div[@class="focus-date clear focus-date-list"]/span[3]/text()').extract()[0].split()[1] #处理状态
number = response.xpath('//div[@class="focus-date clear focus-date-list"]/span[4]/text()').extract()[0].split(':')[-1] #帖子编号
content = response.xpath('//div[@class="details-box"]/pre/text()').extract()[0] #帖子内容
item['title'] = title
item['status'] = status
item['number'] = number
item['content'] = content
yield item
- 以阳光热线问政平台http://wz.sun0769.com/political/index/politicsNewest?id=1为例,爬取投诉帖子的编号、帖子的标题,帖子的处理状态和帖子里的内容。
7、logging功能
Scrapy提供了log功能,通过在setting.py中进行设置,可以被用来配置logging
设置
- LOG_ENABLED:默认: True,启用logging
- LOG_ENCODING:默认: 'utf-8',logging使用的编码
- LOG_FILE:默认::None,在当前目录里创建logging输出文件的文件名
- LOG_LEVEL:默认:'DEBUG',有'CRITICAL'(严重错误)、'ERROR'(一般错误)、'WARNING'(警告信息)、'INFO'(一般信息)、'DEBUG'(调试信息)这5种等级
- LOG_STDOUT:默认: False 如果为 True,进程所有的标准输出(及错误)将会被重定向到log中。
示例:
#在settings.py中任意位置添上以下两句,终端上会清爽很多
LOG_FILE = "xxx.log"
LOG_LEVEL = "INFO"
8、Request对象
GET请求
- 可以使用yield scrapy.Request(url,callback)方法来发送请求
- Request对象初始化方法传入参数如下:
class Request(object_ref): def __init__(self, url, callback=None, method='GET', headers=None, body=None,
cookies=None, meta=None, encoding='utf-8', priority=0,
dont_filter=False, errback=None, flags=None, cb_kwargs=None):
pass - 主要参数:
- url:需要请求并进行下一步处理的url
- callback:指定该请求返回的Response,由哪个函数来处理
- method:默认'GET',一般不需要指定,可以是‘POST’,'PUT'等
- headrs:请求时包含的头文件,一般不需要
- meta:比较常用,在不同的request之间传递数据用的,dict类型
- encoding:使用默认的‘utf-8’就行
- dont_filter:表明该请求不由调度器过滤,可以发送重复请求,默认为False
- errback:指定错误处理函数
POST请求
- 可以使用scrapy.FormRequest(url, formdata, callback)方法进行发送
- 如果希望程序执行一开始就发送POST请求,可以重写Spider类的start_requests(self)方法,并且不再调用start_urls里的url。
- 如果想要预填充或重写像用户名、用户密码这些表单字段, 可以使用 scrapy.FormRequest.from_response(response, formdata, callback) 方法实现。
9、Downloader Middlewares(下载中间件)
- 下载中间件是处于引擎(crawler.engine)和下载器(crawler.engine.download())之间的一层组件,可以有多个下载中间件被加载运行。
- 当引擎传递请求给下载器的过程中,下载中间件可以对请求进行处理 (例如增加http header信息,增加proxy信息等);
- 在下载器完成http请求,传递响应给引擎的过程中, 下载中间件可以对响应进行处理(例如进行gzip的解压等)
- 要激活下载器中间件组件,将其加入到settings.py中的DOWNLOADER_MIDDLEWARES 设置中。 该设置是一个字典(dict),键为中间件类的路径,值为其中间件的顺序(order)。例如:
DOWNLOADER_MIDDLEWARES = {
'myProject.middlewares.MyprojectDownloaderMiddleware': 543,
} - 中间件组件是一个定义了以下一个或多个方法的Python类:
process_request(self, request, spider):当每个request通过下载中间件时,该方法被调用。
process_response(self, request, response, spider):当下载器完成http请求,传递响应给引擎的时候调用
- 示例:(使用随机User-Agent和代理IP)
- middlewares.py文件
import random
import json
import redis from scrapy import signals
from itemadapter import is_item, ItemAdapter
from myProject.settings import USER_AGENTS class MyprojectDownloaderMiddleware:
def __init__(self):
self.r = redis.StrictRedis(host='localhost') #创建redis连接客户端,用于取里面存储的动态获取的代理ip def process_request(self, request, spider):
user_agent = random.choice(USER_AGENTS) #取随机user-Agent
proxy_list = json.loads(self.r.get('proxy_list').decode())
proxy = random.choice(proxy_list) #取随机ip
request.headers.setdefault("User-Agent",user_agent) #设置user-agent
request.meta['proxy'] ='http://'+proxy['ip']+':'+str(proxy['port']) #使用代理ip - 修改settings.py文件配置
#禁用cookies
COOKIES_ENABLED = False #设置下载延迟
DOWNLOAD_DELAY = 3 #添加自己写的下载中间件类
DOWNLOADER_MIDDLEWARES = {
'myProject.middlewares.MyprojectDownloaderMiddleware': 543,
} #添加USER-AGENTS
USER_AGENTS = [
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
"Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
"Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
"Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
"Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
]
- middlewares.py文件
爬虫框架-scrapy的使用的更多相关文章
- 教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
本博文将带领你从入门到精通爬虫框架Scrapy,最终具备爬取任何网页的数据的能力.本文以校花网为例进行爬取,校花网:http://www.xiaohuar.com/,让你体验爬取校花的成就感. Scr ...
- 【转载】教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
原文:教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神 本博文将带领你从入门到精通爬虫框架Scrapy,最终具备爬取任何网页的数据的能力.本文以校花网为例进行爬取,校花网:http:/ ...
- 爬虫框架Scrapy
前面十章爬虫笔记陆陆续续记录了一些简单的Python爬虫知识, 用来解决简单的贴吧下载,绩点运算自然不在话下. 不过要想批量下载大量的内容,比如知乎的所有的问答,那便显得游刃不有余了点. 于是乎,爬虫 ...
- 第三篇:爬虫框架 - Scrapy
前言 Python提供了一个比较实用的爬虫框架 - Scrapy.在这个框架下只要定制好指定的几个模块,就能实现一个爬虫. 本文将讲解Scrapy框架的基本体系结构,以及使用这个框架定制爬虫的具体步骤 ...
- 网络爬虫框架Scrapy简介
作者: 黄进(QQ:7149101) 一. 网络爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本:它是一个自动提取网页的程序,它为搜索引擎从万维 ...
- Linux 安装python爬虫框架 scrapy
Linux 安装python爬虫框架 scrapy http://scrapy.org/ Scrapy是python最好用的一个爬虫框架.要求: python2.7.x. 1. Ubuntu14.04 ...
- Python爬虫框架Scrapy实例(三)数据存储到MongoDB
Python爬虫框架Scrapy实例(三)数据存储到MongoDB任务目标:爬取豆瓣电影top250,将数据存储到MongoDB中. items.py文件复制代码# -*- coding: utf-8 ...
- 《Python3网络爬虫开发实战》PDF+源代码+《精通Python爬虫框架Scrapy》中英文PDF源代码
下载:https://pan.baidu.com/s/1oejHek3Vmu0ZYvp4w9ZLsw <Python 3网络爬虫开发实战>中文PDF+源代码 下载:https://pan. ...
- Python爬虫框架Scrapy教程(1)—入门
最近实验室的项目中有一个需求是这样的,需要爬取若干个(数目不小)网站发布的文章元数据(标题.时间.正文等).问题是这些网站都很老旧和小众,当然也不可能遵守 Microdata 这类标准.这时候所有网页 ...
- 怎么在32位windows系统上搭建爬虫框架scrapy?
禁止转载: 自学python,然后搭建爬虫框架scrapy.费了我一上午的心血.终于搭建成功,以防以后忘记搭建流程,特此撰写此贴,开写 ******************************** ...
随机推荐
- .NET测试断言工具Shouldly
.NET测试断言工具Shouldly .NET测试 Shouldly在GitHub的开源地址:https://github.com/shouldly/shouldly Shouldly的官方文档:ht ...
- MATLAB中FFT_HDL_Optimized模块定点(IEEE754单精度float格式)二进制与十进制转换实现
早些时间段,做了Matlab中FFT_HDL_Optimzed模块FFT HDL代码仿真,并与Xilinx Vivado自带的xfft IP进行单精度浮点比较(后面随笔叙述).因为FFT_HDL_Op ...
- Zeebe服务学习2-状态机
1.什么是状态机? 第一次接触到这个名词,感觉自己是明白这个东东是啥的,但是后来发现,emm-,是的,只是理解了这个词而已. 贴一下官方介绍: 有限状态机,(英语:Finite-state machi ...
- Apache配置 1. 默认虚拟主机
编辑httpd.conf搜索httpd-vhosts,去掉#号 # vi /usr/local/apache2.4/conf/httpd.conf Include conf/extra/httpd-v ...
- web实现时钟效果
纯原生开发时钟效果,话不多说直接上代码. HTML标签部分 <div class="cricles"> <div class="poin ...
- Codeforces Round #574 (Div. 2) D2. Submarine in the Rybinsk Sea (hard edition) 【计算贡献】
一.题目 D2. Submarine in the Rybinsk Sea (hard edition) 二.分析 相比于简单版本,它的复杂地方在于对于不同长度,可能对每个点的贡献可能是有差异的. 但 ...
- Cable Protection
题目大意:求一颗基环树的最小点覆盖. 题解:其实是一道比较板子的树形dp,dp[i][0/1]表示取或者不取i点的最小点.但是首先我们要把基环树断开,然后分别考虑a被覆盖和b被覆盖的情况. dp[i] ...
- 《C++反汇编与逆向分析技术揭秘》--认识启动函数,找到用户入口
<C++反汇编与逆向分析>和<程序员的自我修养>都是以VC6的代码作为例子讲解的.这里是在vs2017下,CRT代码有些区别,但整体流程上都是初始化环境,设置参数,最后转到用户 ...
- Ubuntu18.04美化(Mac OS主题) 美化小白专用
本文主要针对第一次接触Ubuntu美化的童鞋们,有些啰嗦的地方大神勿喷 先上效果图 首先安装神器 gnome-tweak-tool 开启一个终端,输入 sudo apt install gnome-t ...
- Python基础之:Python中的异常和错误
目录 简介 Python中的内置异常类 语法错误 异常 异常处理 抛出异常 异常链 自定义异常 finally 简介 和其他的语言一样,Python中也有异常和错误.在 Python 中,所有异常都是 ...