百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

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)虽然能够生成流畅文本,但...

取消回复欢迎 发表评论: