Scrapy框架进阶篇(scrapy框架的工作流程)
ccwgpt 2024-09-27 07:28 107 浏览 0 评论
1 Scrapy框架进阶篇
1.1 Request
Scrapy 使用 Request和 Request 对象爬取 web 站点。
一般来说,Request 对象在 spider 中被生成并且最终传递到下载器(Downloader),下载器对其进行处理并返回一个 Response 对象,Response 对象还会返回到生成 request 的 spider 中。
22.1.1 Request 对象
一个 Request 对象代表一个 HTTP 请求,一般来讲,HTTP请求是由 Spider 产生并被 Downloader处理进而生成一个 Response。
22.1.2 Request 模块的位置
C:\Python34\Lib\site-packages\scrapy\http\request
22.1.3 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):
self._encoding = encoding # this one has to be set first
self.method = str(method).upper()
self._set_url(url)
self._set_body(body)
assert isinstance(priority, int), "Request priority not an integer: %r" % priority
self.priority = priority
if callback is not None and not callable(callback):
raise TypeError('callback must be a callable, got %s' % type(callback).__name__)
if errback is not None and not callable(errback):
raise TypeError('errback must be a callable, got %s' % type(errback).__name__)
assert callback or not errback, "Cannot use errback without a callback"
self.callback = callback
self.errback = errback
self.cookies = cookies or {}
self.headers = Headers(headers or {}, encoding=encoding)
self.dont_filter = dont_filter
self._meta = dict(meta) if meta else None
self.flags = [] if flags is None else list(flags)
@property
def meta(self):
if self._meta is None:
self._meta = {}
return self._meta
def _get_url(self):
return self._url
def _set_url(self, url):
if not isinstance(url, six.string_types):
raise TypeError('Request url must be str or unicode, got %s:' % type(url).__name__)
s = safe_url_string(url, self.encoding)
self._url = escape_ajax(s)
if ':' not in self._url:
raise ValueError('Missing scheme in request url: %s' % self._url)
url = property(_get_url, obsolete_setter(_set_url, 'url'))
def _get_body(self):
return self._body
def _set_body(self, body):
if body is None:
self._body = b''
else:
self._body = to_bytes(body, self.encoding)
body = property(_get_body, obsolete_setter(_set_body, 'body'))
@property
def encoding(self):
return self._encoding
def __str__(self):
return "<%s %s>" % (self.method, self.url)
__repr__ = __str__
def copy(self):
"""Return a copy of this Request"""
return self.replace()
def replace(self, *args, **kwargs):
"""Create a new Request with the same attributes except for those
given new values.
"""
for x in ['url', 'method', 'headers', 'body', 'cookies', 'meta',
'encoding', 'priority', 'dont_filter', 'callback', 'errback']:
kwargs.setdefault(x, getattr(self, x))
cls = kwargs.pop('cls', self.__class__)
return cls(*args, **kwargs)
22.1.4 Request的初始化构造方法
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)
项目中使用的例子:
scrapy.Request(self.url + str(self.offset), callback = self.parse)
常用的参数:
【url】: 参数类型 string,请求的 url。
【callback】 :处理响应数据的回调方法(指定该请求返回的 Response,由那个函数来处理),用来解析响应数据,如果没有指定,则 spider 的 parse 方法。如果在处理期间引发异常,则会调用 errback。
【method】: 参数类型 string ,HTTP 的请求方法,请求一般不需要指定,默认 GET 方法,可设置为"GET", "POST", "PUT"等,且保证字符串大写
【headers】: 参数类型 dict,请求时,包含的头文件。一般不需要。内容一般如下:
Host: media.readthedocs.org
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
Accept: text/css,*/*;q=0.1
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://scrapy-chs.readthedocs.org/zh_CN/0.24/
Cookie: _ga=GA1.2.1612165614.1415584110;
Connection: keep-alive
【meta】: 参数类型 dict,比较常用,在不同的请求之间传递数据使用的,Request.meta 是属性的初始值。一旦此参数被设置,通过参数传递的字典将会被浅拷贝。
request_with_cookies = Request(
url="http://www.example.com",
cookies={'currency': 'USD', 'country': 'UY'},
meta={'dont_merge_cookies': True}
)
【encoding】: 参数类型 string,编码方式,默认 utf-8。
【dont_filter】: 参数类型 bool,请求不应该被调度器过滤。False 表示过滤,True 表示不过滤。默认 False(当你想使用多次执行相同的请求,忽略重复的过滤器。默认为 False)。
【priority】:参数类型 int,优先级,调度程序使用优先级来定义用于处理请求的顺序,具有较高优先级值的请求将会提前执行,默认0。
【errback】: 指定错误处理函数,如果在处理请求时引发异常,将会调用该函数。 这包括 404 HTTP 错误等失败的页面。
22.1.5 Request.meta
Request.meta 在不同的请求之间传递数据使用。
Request.meta 属性可以包含任意的数据,但是 Scrapy 和它的内置扩展可以识别一些特殊的键。
【dont_redirect】:不重定向
【dont_retry】:不重试
【dont_merge_cookies】:不合并 cookie。
【cookiejar】:使用 cookiejar。
【redirect_urls】:重定向连接。
【bindaddress】:绑定 ip 地址。
【dont_obey_robotstxt】:不遵循反爬虫协议。
【download_timeout】:下载超时。
22.1.5 Request 的子类 FormRequest
FormRequest是 Request 的子类,一般用作表单数据提交。
22.1.6 Request 的子类 FormRequest 模块的位置
C:\Python34\Lib\site-packages\scrapy\http\request 下的 form.py文件。
22.1.7 Request 的子类 FormRequest 源码
class FormRequest(Request):
def __init__(self, *args, **kwargs):
formdata = kwargs.pop('formdata', None)
if formdata and kwargs.get('method') is None:
kwargs['method'] = 'POST'
super(FormRequest, self).__init__(*args, **kwargs)
if formdata:
items = formdata.items() if isinstance(formdata, dict) else formdata
querystr = _urlencode(items, self.encoding)
if self.method == 'POST':
self.headers.setdefault(b'Content-Type', b'application/x-www-form-urlencoded')
self._set_body(querystr)
else:
self._set_url(self.url + ('&' if '?' in self.url else '?') + querystr)
@classmethod
def from_response(cls, response, formname=None, formid=None, formnumber=0, formdata=None,
clickdata=None, dont_click=False, formxpath=None, formcss=None, **kwargs):
kwargs.setdefault('encoding', response.encoding)
if formcss is not None:
from parsel.csstranslator import HTMLTranslator
formxpath = HTMLTranslator().css_to_xpath(formcss)
form = _get_form(response, formname, formid, formnumber, formxpath)
formdata = _get_inputs(form, formdata, dont_click, clickdata, response)
url = _get_form_url(form, kwargs.pop('url', None))
method = kwargs.pop('method', form.method)
return cls(url=url, method=method, formdata=formdata, **kwargs)
22.1.8 FormRequest 的构造
class scrapy.FormRequest(url[,formdata,...])
项目中的示例:
# 构造表单数据,发送 POST 请求登录
scrapy.FormRequest(
url = url,
formdata = {"email" : "13554799061", "password" : "ting123hai"},
callback = self.parse
)
# 回调函数,对返回的 response进行处理请求。
def parse(self, response):
# do something
22.1.8 FormRequest的form_response()方法
FormRequest 类除了有 Request 的功能,还提供一个 form_response()方法:
form_response(response[,formname=None,formnumber=0,formdata=None,formxpath=None,clickdata=None,dont_click=False,...])
form_response 方法参数解析:
【response】:是指包含HTML表单的 Response 对象,该表单将用于预填充表单字段。
【formname】:如果给定,将使用设置为该值的 name 属性的表单。
【formnumber】:当响应包含多个表单时,要使用的表单的数量。 Formnumber 默认是 0,表示使用第一个。
【formdata】:字段来覆盖表单数据。如果一个字段已经存在于响应<form>元素中,那么它的值被在这个参数中传递的值覆盖。
【formxpath】:如果给定,将使用与 XPath 匹配的第一个表单。
【clickdata】:查找单击控件的属性。如果没有给出,表单数据将被提交模拟点击第一个可点击的元素。
【dont_click】:如果为 True,表单数据将被提交而不需要单击任何元素。
1.2 Response
22.2.1 Response对象
HTTP 请求返回的响应对象,它通常被下载(由 Downloader )下载并被传送给 Spider 进行处理。
22.2.2 Response模块的位置
C:\Python34\Lib\site-packages\scrapy\http\response
22.2.3 Response模块的源码
class Response(object_ref):
def __init__(self, url, status=200, headers=None, body=b'', flags=None, request=None):
self.headers = Headers(headers or {})
self.status = int(status)
self._set_body(body)
self._set_url(url)
self.request = request
self.flags = [] if flags is None else list(flags)
@property
def meta(self):
try:
return self.request.meta
except AttributeError:
raise AttributeError(
"Response.meta not available, this response "
"is not tied to any request"
)
def _get_url(self):
return self._url
def _set_url(self, url):
if isinstance(url, str):
self._url = url
else:
raise TypeError('%s url must be str, got %s:' % (type(self).__name__,
type(url).__name__))
url = property(_get_url, obsolete_setter(_set_url, 'url'))
def _get_body(self):
return self._body
def _set_body(self, body):
if body is None:
self._body = b''
elif not isinstance(body, bytes):
raise TypeError(
"Response body must be bytes. "
"If you want to pass unicode body use TextResponse "
"or HtmlResponse.")
else:
self._body = body
body = property(_get_body, obsolete_setter(_set_body, 'body'))
def __str__(self):
return "<%d %s>" % (self.status, self.url)
__repr__ = __str__
def copy(self):
"""Return a copy of this Response"""
return self.replace()
def replace(self, *args, **kwargs):
"""Create a new Response with the same attributes except for those
given new values.
"""
for x in ['url', 'status', 'headers', 'body', 'request', 'flags']:
kwargs.setdefault(x, getattr(self, x))
cls = kwargs.pop('cls', self.__class__)
return cls(*args, **kwargs)
def urljoin(self, url):
"""Join this Response's url with a possible relative url to form an
absolute interpretation of the latter."""
return urljoin(self.url, url)
@property
def text(self):
"""For subclasses of TextResponse, this will return the body
as text (unicode object in Python 2 and str in Python 3)
"""
raise AttributeError("Response content isn't text")
def css(self, *a, **kw):
"""Shortcut method implemented only by responses whose content
is text (subclasses of TextResponse).
"""
raise NotSupported("Response content isn't text")
def xpath(self, *a, **kw):
"""Shortcut method implemented only by responses whose content
is text (subclasses of TextResponse).
"""
raise NotSupported("Response content isn't text")
def follow(self, url, callback=None, method='GET', headers=None, body=None,
cookies=None, meta=None, encoding='utf-8', priority=0,
dont_filter=False, errback=None):
# type: (...) -> Request
if isinstance(url, Link):
url = url.url
url = self.urljoin(url)
return Request(url, callback,
method=method,
headers=headers,
body=body,
cookies=cookies,
meta=meta,
encoding=encoding,
priority=priority,
dont_filter=dont_filter,
errback=errback)
22.2.4 Response的构造
class scrapy.Response(url[,status=200,headers,body,flags])
参数解析:
【url】:响应对象 response 的url 。
【headers】:响应对象的响应报头。
【status】:响应的状态码,默认 200。
【body】:响应体。
【meta】:为 response.meta 属性的初始值。如果给定的,字典将浅复制。
【flags】:是一个列表包含的 response.flags 初始值的属性。如果给定,列表将被浅拷贝。
22.2.5 Response的子类
(一)TextResponse类
class scrapy.TextResponse(url[,encoding[,...]])
TextResponse 对象增加了编码能力的基础响应类,是指将只用于二进制数据,如图像、声音或任何媒体文件。
TextResponse 对象除了标准的 Response对象外,还支持以下属性和方法:
【encoding】
与此响应编码的字符串。 通过尝试以下机制来解决编码问题:
.在构造函数编码参数中传递的编码
.在Content-Type HTTP 头中声明的编码。如果这种编码是无效的(即未知的),它将被忽略,并尝试下一个解析机制。
.在响应正文中声明的编码。TextResponse 类不提供任何特殊的功能。但是,HtmlResponse 和XmlResponse 类可以。
.通过查看响应主体来推断编码。 这是更脆弱的方法,但也是最后一个尝试。
【selector】:使用响应作为目标的选择器实例。
【body_as_unicode()】:以 Unicode 形式返回响应的主体。
【xpath(query)】:xpath 解析。
textresponse.selector.xpath('//p')可以简写成 textresponse.xpath('//p')。
项目中例子:
# 标题
item['title'] = response.xpath('//div[contains(@class, "pagecenter p3")]//strong/text()').extract()[0]
【css(query)】:css 解析,相当于 BeautifulSoup4 解析
textresponse.selector.css('p')也可以简写为 :textresponse.css('p')。
(二)HtmlResponse 类
HtmlResponse 类是 TextResponse 的一个子类,它通过查看 HTML meta http-equiv 属性来添加编码自动发现支持。
(三)XmlResponse 类
XmlResponse 类是 TextResponse 的一个子类,它通过查看 XML 声明行来添加编码自动发现支持。
1.3 防止爬虫被反通用策略
防止爬虫被反通用策:
.动态设置 User-Agent(随机切换 User-Agent,模拟不同用户的浏览器信息)
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"
]
.禁用 Cookies(也就是不启用 cookies middleware,不向 Server 发送 cookies,有些网站通过 cookie 的使用发现爬虫行为)。
可以通过 COOKIES_ENABLED 控制 Cookies Middleware 开启或关闭。
.设置延迟下载(防止访问过于频繁,设置为 2 秒 或更高)
.Google Cache 和 Baidu Cache:如果可能的话,使用谷歌/百度等搜索引擎服务器页面缓存获取页面数据。
.使用IP地址池:VPN和代理IP,现在大部分网站都是根据IP。
.使用 Crawlera(专用于爬虫的代理组件),正确配置和设置下载中间件后,项目所有的 request 都是通过 crawlera 发出。
DOWNLOADER_MIDDLEWARES = {
'scrapy_crawlera.CrawleraMiddleware': 600
}
CRAWLERA_ENABLED = True
CRAWLERA_USER = '注册/购买的UserKey'
CRAWLERA_PASS = '注册/购买的Password'
1.4 下载中间件(Downloader Middlewares)
下载中间件是处于引擎( crawler.engine )和下载器( crawler.engine.download() )之间的一层组件,可以有多个下载中间件被加载运行。
当引擎传递请求给下载器的过程中,下载中间件可以对请求进行处理 (例如增加 http header 信息,增加 proxy 信息等);
在下载器完成 http 请求,传递响应给引擎的过程中, 下载中间件可以对响应进行处理(例如进行 gzip 的解压等)
要激活下载器中间件组件,将其加入到 DOWNLOADER_MIDDLEWARES 设置中。该设置是一个字典( dict ),键为中间件类的路径,值为其中间件的顺序( order )。
例子:
DOWNLOADER_MIDDLEWARES = {
'mySpider.middlewares.MyDownloaderMiddleware': 543,
}
编写下载器中间件十分简单。每个中间件组件是一个定义了以下一个或多个方法的Python类:
class scrapy.contrib.downloadermiddleware.DownloaderMiddleware
22.4.1 process_request(self, request, spider)
当每个 request 通过下载中间件时,该方法被调用。
process_request() 必须返回以下其中之一:一个 None 、一个 Response 对象、一个 Request 对象或 raise IgnoreRequest:
如果其返回 None ,Scrapy 将继续处理该 request,执行其他的中间件的相应方法,直到合适的下载器处理函数( download handler )被调用, 该 request 被执行(其 response 被下载)。
如果其返回 Response 对象,Scrapy 将不会调用 任何 其他的 process_request() 或 process_exception() 方法,或相应地下载函数; 其将返回该 response。 已安装的中间件的 process_response() 方法则会在每个 response 返回时被调用。
如果其返回 Request 对象,Scrapy 则停止调用 process_request方法并重新调度返回的request。当新返回的 request 被执行后, 相应地中间件链将会根据下载的 response 被调用。
如果其 raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则 request 的 errback( Request.errback )方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。
参数:
【request (Request 对象)】:处理的 request。
【spider (Spider 对象)】 :该 request 对应的 spider。
22.4.2 process_response(self, request, response, spider)
当下载器完成 http 请求,传递响应给引擎的时候调用。
process_request() 必须返回以下其中之一: 返回一个 Response 对象、 返回一个 Request 对象或 raise一个 IgnoreRequest 异常。
如果其返回一个 Response (可以与传入的 response 相同,也可以是全新的对象), 该response 会被在链中的其他中间件的 process_response() 方法处理。
如果其返回一个 Request 对象,则中间件链停止, 返回的 request 会被重新调度下载。处理类似于 process_request() 返回 request 所做的那样。
如果其抛出一个 IgnoreRequest 异常,则调用request的errback(Request.errback)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)。
参数:
【request (Request 对象)】 : response 所对应的 request。
【response (Response 对象)】 : 被处理的 response。
【spider (Spider 对象)】 : response 所对应的 spider。
22.4.3 案例
1、 创建 middlewares.py 文件。
Scrapy 代理 IP、Uesr-Agent 的切换都是通过 DOWNLOADER_MIDDLEWARES 进行控制,我们在settings.py 同级目录下创建 middlewares.py 文件,包装所有请求。
import random
import base64
from settings import USER_AGENTS
from settings import PROXIES
# 随机的User-Agent
class RandomUserAgent(object):
def process_request(self, request, spider):
useragent = random.choice(USER_AGENTS)
request.headers.setdefault("User-Agent", useragent)
class RandomProxy(object):
def process_request(self, request, spider):
proxy = random.choice(PROXIES)
if proxy['user_passwd'] is None:
# 没有代理账户验证的代理使用方式
request.meta['proxy'] = "http://" + proxy['ip_port']
else:
# 对账户密码进行base64编码转换
base64_userpasswd = base64.b64encode(proxy['user_passwd'])
# 对应到代理服务器的信令格式里
request.headers['Proxy-Authorization'] = 'Basic ' + base64_userpasswd
request.meta['proxy'] = "http://" + proxy['ip_port']
为什么 HTTP 代理要使用 base64 编码:
HTTP 代理的原理很简单,就是通过 HTTP 协议与代理服务器建立连接,协议信令中包含要连接到的远程主机的IP和端口号,如果有需要身份验证的话还需要加上授权信息,服务器收到信令后首先进行身份验证,通过后便与远程主机建立连接,连接成功之后会返回给客户端 200,表示验证通过,就这么简单,下面是具体的信令格式:
CONNECT 59.64.128.198:21 HTTP/1.1
Host: 59.64.128.198:21
Proxy-Authorization: Basic bGV2I1TU5OTIz
User-Agent: OpenFetion
其中 Proxy-Authorization 是身份验证信息,Basic 后面的字符串是用户名和密码组合后进行 base64 编码的结果,也就是对 username:password 进行 base64 编码。
HTTP/1.0 200 Connection established
OK,客户端收到收面的信令后表示成功建立连接,接下来要发送给远程主机的数据就可以发送给代理服务器了,代理服务器建立连接后会在根据IP地址和端口号对应的连接放入缓存,收到信令后再根据IP地址和端口号从缓存中找到对应的连接,将数据通过该连接转发出去。
2、 修改 settings.py 配置 USER_AGENTS 和 PROXIES 。
添加 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"
]
添加代理IP设置PROXIES:
免费代理 IP 可以网上搜索,或者付费购买一批可用的私密代理IP:
PROXIES = [
{'ip_port': '111.8.60.9:8123', 'user_passwd': 'user1:pass1'},
{'ip_port': '101.71.27.120:80', 'user_passwd': 'user2:pass2'},
{'ip_port': '122.96.59.104:80', 'user_passwd': 'user3:pass3'},
{'ip_port': '122.224.249.122:8088', 'user_passwd': 'user4:pass4'},
]
3、除非特殊需要,禁用cookies,防止某些网站根据Cookie来封锁爬虫。
COOKIES_ENABLED = False
4、设置下载延迟
DOWNLOAD_DELAY = 3
5、最后设置setting.py里的DOWNLOADER_MIDDLEWARES,添加自己编写的下载中间件类。
DOWNLOADER_MIDDLEWARES = {
#'mySpider.middlewares.MyCustomDownloaderMiddleware': 543,
'mySpider.middlewares.RandomUserAgent': 1,
'mySpider.middlewares.ProxyMiddleware': 100
}
相关推荐
- css布局方案汇总(28个实例图文并茂)
-
简介布局在我们前端日常开发来说是非常重要的,一个好的布局能简化代码的同时还能提高网页的性能。常见的布局方法有浮动(float)布局、绝对定位(position)布局、表格布局(table)、弹性(fl...
- 十款免费的CSS框架加速Web开发
-
Pure这是Yahoo最新推出的一款CSS框架,它只有HTML和CSS,没有使用任何JavaScript语言。总大小只有4.4kb,但功能却非常丰富,支持响应式样式和各种导航、表格、表单、按钮、网格和...
- Tailwind CSS 是不是目前世上最好的CSS框架?
-
转载说明:原创不易,未经授权,谢绝任何形式的转载今天看了一篇国外大佬对TailwindCSS的看法,在这里分享给大家,看看大家是否赞同,以下是其相关内容的整理,由于翻译水平有限,欢迎大家讨论和指...
- 下一代 CSS 框架:Mojo CSS,为何如此受欢迎?
-
TailwindCSS推出即受到广大开发者的欢迎,当前Githubstar数已达77.8k。它是一个功能类优先(utility-first)的CSS框架,它提供了一系列功能类,让开发者...
- 常见的几种摄影构图方式
-
摄影构图,是一种在摄影画面中表现结构美、形式美的方式。构图能让摄影主体更加突出,画面更加有序。所以说,构图在摄影中是非常重要的一个环节。无论是前期构图还是后期构图,摄影者都要对构图有一个比较深的了解。...
- 风光摄影10大构图技巧,会用构图,照片更容易好看
-
风光摄影10大构图技巧,会用构图,照片更容易好看先解释一下,为什么会使用构图之后,照片更容易好看?因为,构图是根据很多好看的照片,总结出来的技巧,使用这些构图技巧,就相当于站在了巨人的肩膀上,也就是用...
- 掌握框式构图的摄影技巧,会让摄影爱好者的作品更有魅力!
-
很多摄影爱好者都知道摄影构图中有个框式构图,但大多数人对框式构图的摄影技巧,却一知半解。所以摄影爱好者们有必要更全面、深入的了解,并掌握框式构图,会对你摄影水平的提高更有帮助。【欢迎点击上方关注:金立...
- 这个构图很简洁,但为什么不耐看?
-
摄影爱好者最常犯的错就是过于复杂、主体不明确,但当遇到简单的场景往往又会出现单调、不耐看的状况。为什么会这样?说白了还是观察力不够。下面是本周的摄影入围习作,我们一起来看看这些照片中主体、陪体以及背景...
- 初学者需要记牢的八种常用构图法
-
作者:冯海军摄影中,构图很关键,决定照片是否成功,所以在构图上要加以重视和推敲,虽然说构图无定法,但是也有很多的规律可循,以下列举几种常用构图,会对初学者有很大的帮助。多彩刘卫洲摄苏州姑苏俱乐部(...
- 构图这件事不难!掌握14种构图模式就稳了
-
如果说视觉元素是视觉信息的载体,那么构图就是视觉元素的载体。没有适当形式的构图对视觉元素有机、有序地承载,平面设计将无法传达预定的设计意图和视觉信息。因此,对于平面设计而言,构图是平面设计不可或缺的重...
- 框架构图如何使用?
-
1分钟教你用手机拍大片。今天我们利用框架构图,在不同的运镜方法下拍摄。·首先将手机贴近地面,拍摄人物走过的画面。·然后利用3D效果的背景衬托,将手机贴近地面,以低角度仰拍人物。·最后我们用高清画质来呈...
- 面构图的5种超实用的构图形式 前景构图,框架构图,填充构图
-
面构图的5种超实用的构图形式。为什么有的人拍摄的照片好看又舒适?仔细观察会发现他们善用构图。大家好,今天带大家了解摄影中5种超实用的面构图形式。·一、前景构图。前景是构图中的神奇要素,可以提升照片的表...
- 一看就懂!跟着马格南的大师学构图
-
马格南图片社是迄今为止全球最重要的摄影图片社,其网站包涵了太多经典的名字和照片。细细品味这些经典图片,能够学到很多有用的构图手法。跟着大师走,总不会错吧?前后景的运用这似乎是非常常见的一种手法,仔细看...
- 这才是框架构图,有想法!能给你启发么?
-
框架构图大家并不陌生,但并不是有一个框就行了。框架构图用得不好,就很死板生硬,给人感觉很假。如果你理解透了,拍出的作品不会单调。今天就给大家分享一下框架构图,你看看有哪些妙用?1.广角与长焦的应用长焦...
- 7B小模型写好学术论文,新框架告别AI引用幻觉
-
ScholarCopilot团队投稿量子位|公众号QbitAI学术写作通常需要花费大量精力查询文献引用,而以ChatGPT、GPT-4等为代表的通用大语言模型(LLM)虽然能够生成流畅文本,但...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 若依框架 (41)
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- scrapy框架 (52)
- beego框架 (42)
- java框架spring (43)
- grpc框架 (55)
- 前端框架bootstrap (42)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle v (42)
- oracle字符串长度 (48)
- oracle提交事务 (47)