整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

小R智能编程机器人

小R智能编程机器人

东众筹网址链接:https://z.jd.com/project/details/1816856838.html

编程是不是该从小学起,看完这篇,或许你心中会有答案

假如你也曾经是个游戏迷,那么,这款曾风靡一时的《我的世界》,相信你应该不会太过陌生。


在这款极具开放性的游戏里,玩家能够凭借自己无尽的想象力,打造、创造一个只属于自己的世界,这就是《我的世界》的魅力。


其实,早在很久以前,许多家长,培训机构,甚至是校园,就已经意识到了乐高对孩子智力开发的重要性。加强孩子这方面的培养和教育,一来能够培养孩子的空间想象力,二来还能培养孩子的自我创造能力。


倘若再将编程的思维融入其中,甚至还能培养孩子的机器人设计能力,同时在这个过程中,提高他们的专注能力。

正因为发现了编程的重要性,甚至连国家都“强插一手”,在部分地区,将计算机编程这门科目,纳入了高考。

其实,早在2016年的美国,政府就已经将计算机编程的成绩算进了高中毕业的学分之中;而2017年的英国,甚至都将学习编程这项科目,纳入了小学必修课程当中。我们在这个时候才意识到编程的重要性,虽然还不算太迟,但若不开始抓紧,那就很有可能再一次与世界拉开一段距离。


其实仔细想想就会明白,无论是被人们封神的苹果创始人乔布斯、或是福布斯首富兼微软创始人比尔盖茨无一不是从小就开始学习编程,然后终此一生投身于科技事业,这些无一不在编程的重要性。

那么,问题就来了,应该如何从小开始学习编程呢?是应该加入培训班吗?毕竟编程这种的课程不是语数英,一般父母很少接触,想让每个父母在孩子小的时候就手把手教,这并不现实。


其实吧,学习这种东西,最重要看兴趣,在孩子小的时候就强行将孩子送入教育“味道”过于浓厚的培训机构中,不仅可能无法让孩子对编程产生兴趣,甚至会让孩子未来对编程这门课产生阴影。因此,娱乐性就很重要了。

其实让孩子从小开始接触编程的话,给孩子选一台兼具娱乐性和教育性的编程机器人是一个不错的选择。在这一方面,小二极客团队就很有发言权了。


这是一个深耕编程机器人开发多年的专业团队,在提供了小R编程机器人系列的同时,还提供了易用的套件、先进的代码结构、快捷的开发方式,更重要的是,还提供了一整套易入门的电子类课程,全面为孩子们提供了一套以寓教于乐为中心的系统教育教学机器人系列。

说到小R编程机器人,不得不安利一下这款由小二极客团队最新研发的这款人形机器人了。

人形的外观,对于孩子来说,是具有绝对的亲切感的。这样的设计,打破了以往机器人给人的冰冷的感觉。


还注入了多种多样的互动元素。

摸摸头,自行启动卖萌技能

来一段节奏,跳个舞给你看

还能做指南针,帮孩子复习一下地理

这些事先设定好的程序代码,孩子既可以通过软件直接导入,也可以自行重新编入,有趣好玩,孩子学起来也开心。

至于编程的开发板也很良心,是可以兼容业内常用的micro:bit编程方式的开发板,在中小学生编程教育中十分流行,编程画面十分有趣,孩子可以轻松上手。

手机端、PC端都可用,孩子喜欢用哪个平台就用哪个平台。

还有一整套完善的编程课程,让孩子学习编程就像玩一样简单。

除了编程,他还是孩子休闲是的遥控机器人,闲暇时候,还能跟隔壁孩子一起来场“机器人”对决。

现在,这款小R编程机器人正在京东众筹平台火热众筹中,登陆京东众筹页面,输入关键词“小R智能编程机器人”即可了解更多详情。

  • 基本使用
    • 发送请求
    • 解析响应获
  • 获取需要的内容
    • 快速获取链接
    • 获取元素
  • 高级功能
    • JS渲染
    • 自动翻页(不太好用)
  • 异步
    • 异步渲染JS
    • 异步发送请求

初识requests_html模块

感觉只要学过Python爬虫的同学应该都知道requests这个库吧,它在我们的Python爬虫任务中应该是最常用的一个库了!今天跟大家分享的这个模块requests_html,他的作者和前者是同一人!这是一个解析HTML的库,用起来和requests一样方便,下面就来介绍一下它!

  • 参考视频

使用requests_html

安装

  • 依然是那个命令 pip3 install -i https://pypi.doubanio.com/simple requests_html
  • 注意:由于requests_html模块中使用了异步asynico模块,所以官方声明,需要在python3.6以上版本才能正常使用!

基本使用

发送请求

  • requests_html发送请求获取页面需要先实例化一个HTMLSession对象,然后使用get/post...方法获取响应,如下列代码
#!/usr/bin/env python3
# coding     : utf-8
# Author     : xiao qiang
# 微信公众号   : xiaoqiangclub
# Software   : PyCharm
# File       : test.py
# Time       : 2021/5/29 7:57
from requests_html import HTMLSession

if __name__ == '__main__':
    url = 'https://wwww.baidu.com'
    session = HTMLSession()  # 获取实例化session对象
    r = session.get(url)    # 这里的请求和requests的几乎一样!同样可以根据需要添加headers等参数
  • requests_html发送请求的方式和requests中使用session方式发送请求几乎是一样的,可以对比参考
  • requests_html同样可以发送get/post等请求,且可以和requests同样携带headers/data等参数,具体用法参考requests

解析响应获

  • 接上,我们需要将获取的响应解析获取html页面,在这里我们同样可以使用requests中的r.content.decode()等原方法!
  • 但是在requests_html中还提供了更便捷的方法:r.html.html
  • r.html.html实际上是使用了requests_html中的HTML类(负责对HTML进行解析)来进行解析!如下
#!/usr/bin/env python3
# coding     : utf-8
# Author     : xiao qiang
# 微信公众号   : xiaoqiangclub
# Software   : PyCharm
# File       : test.py
# Time       : 2021/5/29 7:57
from requests_html import HTMLSession

if __name__ == '__main__':
    url = 'https://wwww.baidu.com'
    session = HTMLSession()  # 获取实例化session对象
    r = session.get(url)  # 这里的请求和requests的几乎一样!同样可以根据需要添加headers等参数

    # 获取html页面
    # html = r.content.decode()  # requests方式
    get_html = r.html.html  # requests_html中的方法
    print(get_html[:15], '...')
  • 运行结果(这里只显示了部分结果!)

获取需要的内容

快速获取链接

  • requests_html中提供了快速获取网址链接的方法
  • 使用linksabsolute_links两个属性分别可以返回HTML对象所包含的所有链接和绝对链接(均不包含锚点)
# 快速获取链接
pprint(r.html.links)  # 获取html中的链接(href属性)
pprint(r.html.absolute_links)  # 会自动拼接url生成绝对链接
  • 部分运行结果如下

获取元素

  • requests_html中的HTML对象可以直接使用xpathcss选择器

使用xpath

  • requests_html中的HTML对象支持xpath语法,它有以下几个参数:
def xpath(self, selector: str, *, clean: bool = False, first: bool = False, _encoding: str = None) -> _XPath:
- selector,要用的 xpath选择器;
- clean,布尔值,如果为True,会清除HTML中style和script标签;
- first,布尔值,如果为True,会返回第一个元素,否则会返回满足条件的元素列表;
- _encoding,编码格式。
  • 接上面的例子!使用获取到的响应得到HTML对象r.html
pprint(r.html.xpath('//li[@class="hotsearch-item odd"]/a'))
pprint(r.html.xpath('//li[@class="hotsearch-item odd"]/a', first=True).text)
  • 运行结果
  • xpath语法

使用css选择器(find方法)

  • requests_html中的HTML对象支持css选择器,它有以下几个参数:
def find(self, selector: str = "*", *, containing: _Containing = None, clean: bool = False, first: bool = False, _encoding: str = None) -> _Find:
- selector,要用的CSS选择器;
- clean,布尔值,如果为True,会清除HTML中style和script标签;
- containing,如果设置该属性,只返回包含该属性文本的标签;
- first,布尔值,如果为True,会返回第一个元素,否则会返回满足条件的元素列表;
- _encoding,编码格式。
  • 接上面的例子!使用获取到的响应得到HTML对象r.html
pprint(r.html.find('a.mnav'))
pprint(r.html.find('a.mnav', first=True).text)
  • 运行结果
  • css选择器语法
  • 可以使用text属性来获取元素的文本内容

pprint(r.html.find('a.mnav')[0].text)

  • 执行结果
  • 如果要获取元素的attribute,用attrs属性

pprint(r.html.find('a.mnav')[0].attrs)

  • 执行结果
  • 获取到attrs属性后,就可以使用字典的相关方法获取内容了!
  • 最后还可以使用html属性获取一个元素的html代码,如下

pprint(r.html.find('a.mnav')[0].html)

  • 执行结果

正则搜索(search、search_all)

  • requests_html除了上面的方式还可以使用search/search_all来直接搜索内容,返回的是一个Result对象/Result对象列表实际上是作者将re正则进行了封装)!
def search(self, template: str) -> Result:
# 只有一个参数
template: 就是要检索的内容,这里使用英文状态的 {} 来获取内容,有点类似正则里面的 ()
  • 使用英文状态的 {} 来获取内容,如下
    ret = r.html.find('a.mnav')[0].search('新{}')
    pprint(ret)
    pprint(type(ret))
    pprint(ret[0])
  • 执行结果
  • search()获取到的是第一个匹配的对象,而searchh_all()则是获取所有匹配的对象,得到的是一个列表,如下

ret=r.html.find('a.mnav')[0].search_all('新{}')
pprint(ret)
pprint(type(ret))
pprint(ret[0][0])

  • 运行结果
  • 除了对某个元素进行检索外,还可以直接对html对象进行搜索,如下

ret=r.html.search_all('百度{}')
pprint(ret)
pprint(type(ret))
pprint(ret[0][0])

  • 运行结果
  • requests_html内容提取的方式这么多,大家可以根据需要和习惯选择使用!

search补充

  • 在上面提到的search()/search_all()方法中,我们设定的template参数可以有多个取值(多个{}),得到的结果是一个列表,我们可以遍历别表进行取值 取值的时候可以通过result[索引]的方式进行获取对应的数据,如下(示例部分代码) search_ret=r.html.search_all('<a h{}f="{}"',)
    print(search_ret)
    for ret in search_ret:
    print(ret)
    print(ret[1])
    print('--------------')
    运行结果(部分)
  • 除此之外,我们还可以对取值进行命名,返回的结果是可以使用类似字典(不是字典)[name]的方式取值(不能使用get),如下示例(部分代码) search_ret=r.html.search_all('<a h{test}f="{url}"',)
    print(search_ret)
    for ret in search_ret:
    print(ret)
    print(ret['name'])
    print('--------------')
  • 运行结果(部分)
  • 以上就是对requests_html模块search()/search_all()方法的补充内容!

HTML类

  • requests_html中使用HTML类负责对HTML进行解析
  • HTML类不仅可以解析网络请求获取的响应,还可以直接解析html文本,如下
>>> from requests_html import HTML
>>> doc = """<a href='https://www.baidu.com'>"""

>>> html = HTML(html=doc)
>>> html.links
{'https://www.baidu.com'}
  • 还可以直接渲染JS,如下
# 和上面一段代码接起来
>>> script = """
        () => {
            return {
                width: document.documentElement.clientWidth,
                height: document.documentElement.clientHeight,
                deviceScaleFactor: window.devicePixelRatio,
            }
        }
    """
>>> val = html.render(script=script, reload=False) # render()方法 后面会讲

>>> print(val)
{'width': 800, 'height': 600, 'deviceScaleFactor': 1}

>>> print(html.html)
<html><head></head><body><a href="https://www.baidu.com"></a></body></html>

高级功能

  • 前面介绍的是requests_htmlrequests库的基础上整合的html解析&数据筛选的功能!
  • 下面要为大家介绍的是requests_html模块中的一些高级功能:自动渲染JS&智能分页

JS渲染

  • 我们在做爬虫项目的时候会遇到网站的页面是由js生成的情况!这个时候要么就是自己去一步一步地分析请求,要么就是使用selenium等第三方库来进行渲染页面,为了解决这个难题,requests_html模块中引进了pyppeteer,使用pyppeteer可以像使用selenium一样实现网站的完整加载!而且pyppeteer是一个异步模块!效率会更高!
  • requests_html模块在HTML对象的基础上使用render()方法重新加载js页面
  • 注意:在第一次使用render()的时候,系统在用户目录(默认是~/.pyppeteer/)中下载一个chromium。下载过程只在第一次执行,以后就可以直接使用chromium来执行任务了。在没有科学上网的环境下可能下载速度有点慢,请耐心等待...
  • 下面是一个官方示例
>>> r = session.get('http://python-requests.org/')

>>> r.html.render()
[W:pyppeteer.chromium_downloader] start chromium download.
Download may take a few minutes.
[W:pyppeteer.chromium_downloader] chromium download done.
[W:pyppeteer.chromium_downloader] chromium extracted to: C:\Users\xxxx\.pyppeteer\local-chromium\571375
>>> r.html.search('Python 2 will retire in only {months} months!')['months']
'<time>25</time>'
  • requests_html模块在HTML对象的基础上使用render()方法重新加载js页面,它有以下几个参数:
def render(self, retries: int = 8, script: str = None, wait: float = 0.2, scrolldown=False, sleep: int = 0, reload: bool = True, timeout: Union[float, int] = 8.0, keep_page: bool = False):
- retries: 加载页面失败的次数
- script: 页面上需要执行的JS脚本(可选)
- wait: 加载页面前等待的时间(秒),防止超时(可选)
- scrolldown: 页面向下滚动的次数(整数)
- sleep: 在页面初次渲染之后的等待时间
- reload: 如果为False,那么页面不会从浏览器中加载,而是从内存中加载,只有设置为True才会在浏览器中渲染JS
- keep_page: 如果为True,允许您使用 r.html.page 访问浏览器页面
  • requests_html还支持异步渲染JS[^1]

自动翻页(不太好用)

  • 很多网站会出现翻页的情况,requests_html模块的HTML对象中提供了一个next()方法来实现自动翻页!
  • requests_html模块在HTML对象的基础上使用next()方法来实现自动翻页!它有以下几个参数:
def next(self, fetch: bool = False, next_symbol: _NextSymbol = DEFAULT_NEXT_SYMBOL) -> _Next:
fetch: 一个布尔型参数,默认为False:直接返回下一页的 url地址;
       如果设置为True:则直接返回下一页的 HTML对象
  • 这个方法我自己测试了一下,只有一些特定的网站才能实现这个功能,requests_html在的源码中可以看到,作者通过搜索包含'next', 'more', 'older'字段的a标签(因为一般情况下我们的下一页url就是在a标签下的href属性中),所以只有满足了他的条件才会实现这个功能(也就是说HTML页面不按照这个套路它就无法实现这个功能!),下面是部分源码
DEFAULT_NEXT_SYMBOL = ['next', 'more', 'older']
# next()方法
    def next(self, fetch: bool = False, next_symbol: _NextSymbol = DEFAULT_NEXT_SYMBOL) -> _Next:
        """Attempts to find the next page, if there is one. If ``fetch``
        is ``True`` (default), returns :class:`HTML <HTML>` object of
        next page. If ``fetch`` is ``False``, simply returns the next URL.

        """

        def get_next():
            candidates = self.find('a', containing=next_symbol) # 寻找 包含字段'next', 'more', 'older' 的a标签
  • 这里我就不做举例了,大家可以自行去尝试!

异步

  • requests_html中还支持了异步功能
  • requests_html是使用了asynico来封装了一些异步操作,所以这里的一些操作会用到asynico库相关的一些知识,如果您还不太了解,请自行学习!

异步渲染JS

  • 前面我们介绍了使用render()方法渲染JS,其实它还支持异步渲染
  • 一般异步渲染使用在我们有多个页面需要进行渲染的情况下,因为只要在多任务的时候才能体现出异步的高效率,它有以下几个参数:
def __init__(self, loop=None, workers=None, mock_browser: bool = True, *args, **kwargs):
loop: 使用的Asyncio循环。
workers: 用于执行异步调用的线程数量。如果不传递,它将默认为电脑处理器数量乘以5
  • 更多的异步使用方法请参考asyncio库的使用方法,下面是一个官方示例
>>> async def get_pyclock():
...     r = await asession.get('https://pythonclock.org/')
...     await r.html.arender()
...     return r
...
>>> results = asession.run(get_pyclock, get_pyclock, get_pyclock) # 这里作者将同一个页面使用异步方式进行了3次渲染,但是实际上使用的时间并不是平时的3倍!可能只是比平时渲染一个页面多花了一点时间而已!这就是异步的好处!
  • 注意:results是一个列表

异步传参

  • 这里是后面加的内容,因为我突然想到有时候我们的函数有可能是带参数的,那么这个时候我们可以使用lambda来进行传参,看下面示例
#!/usr/bin/env python
# -*- encoding: utf-8 -*-                            
# @Author     : xiao qiang
# @WeChat     : xiaoqiangclub                              
# @Software   : PyCharm      
# @File       : test002.py
# @Time       : 2021/5/30 19:48
from requests_html import AsyncHTMLSession

aSession = AsyncHTMLSession()


async def test(tt, yy):
    r = await aSession.get('https://www.baidu.com/')
    await r.html.arender()
    print('-{}-{}-'.format(tt, yy))
    return r


ret1 = aSession.run(lambda: test('1', 'a'))
ret2 = aSession.run(lambda: test('2', 'b'))
ret3 = aSession.run(lambda: test('3', 'c'))
print(ret1)
print(ret2)
print(ret3)
  • 注意:这里ret1/ret2/ret3都是列表
  • 运行结果
  • 上面的示例还可以这样写

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# @Author : xiao qiang
# @WeChat : xiaoqiangclub
# @Software : PyCharm
# @File : test002.py
# @Time : 2021/5/30 19:48
from requests_html import AsyncHTMLSession
aSession=AsyncHTMLSession()
async def test(tt, yy):
r=await aSession.get('https://www.baidu.com/')
await r.html.arender()
print('-{}-{}-'.format(tt, yy))
return r
# ret1=aSession.run(lambda: test('1', 'a'))
# ret2=aSession.run(lambda: test('2', 'b'))
# ret3=aSession.run(lambda: test('3', 'c'))
# print(ret1)
# print(ret2)
# print(ret3)
#
test_dict={
'1': 'a',
'2': 'b',
'3': 'c'
}
tasks=[lambda i=i, y=y: test(i, y) for i, y in
test_dict.items()]
# lambda传参误区参考文章:https://www.jianshu.com/p/58ebd1618556
ret=aSession.run(*tasks)
# 注意前面有个 *,不可少!# 参考文章:https://www.jianshu.com/p/58ebd1618556
print(ret)

  • 这里在使用lambda传参的时候可能会出现一个错误,可以参考文章解决!
  • 运行结果

异步发送请求

  • 我们在做爬虫的时候,特别是大型爬虫的时候,需要对很多页面进行操作,或者说是需要发送很多请求,也就是需要进行很多IO操作。所以,使用异步发送请求能显著地提升我们的爬虫效率!
  • requests_html模块中,设置了一个AsyncHTMLSession类来实现发送异步请求
  • ,下面是一个官方示例
>>> from requests_html import AsyncHTMLSession
>>> asession = AsyncHTMLSession()
>>> async def get_pythonorg():
...     r = await asession.get('https://python.org/')
...     return r
...
>>> async def get_reddit():
...    r = await asession.get('https://reddit.com/')
...    return r
...
>>> async def get_google():
...    r = await asession.get('https://google.com/')
...    return r
...
>>> results = asession.run(get_pythonorg, get_reddit, get_google)
>>> results # check the requests all returned a 200 (success) code
[<Response [200]>, <Response [200]>, <Response [200]>]
>>> # Each item in the results list is a response object and can be interacted with as such
>>> for result in results:
...     print(result.html.url)
...
https://www.python.org/
https://www.google.com/
https://www.reddit.com/
  • 上面的示例用到了asynico库中一些相关的知识,如果您还不太了解,请自行学习!

总结

  • requests_html模块requests库的基础上封装了页面解析数据清理的功能,并且添加了对当前比较流行的异步操作,让我们在做爬虫项目(一般项目)的时候无需再去使用多个第三方模块来实现功能,几乎是提供了一站式的服务!
  • 所以Python写爬虫使用requests_html就对了!(当然大项目还是首选scrapy,个人愚见!)
  • 更多内容

视频讲解源码

from requests_html import HTMLSession, HTML, AsyncHTMLSession
from pprint import pprint


class DouBanTest:
    def __init__(self):
        self.start_url = 'https://movie.douban.com/chart'  # 豆瓣电影排行榜url
        self.js_url = 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0'
        self.session = HTMLSession()  # 实例化session
        self.aSession = AsyncHTMLSession()  # 实例化异步session
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
        }

    def get_response(self, url):
        """获取响应,并返回requests_html中的HTML对象"""
        r = self.session.get(url, headers=self.headers)
        # print(r)

        return r.html

    # 快速获取页面中的url
    def fast_get_urls(self):
        """快速获取页面中的url"""
        html = self.get_response(self.start_url)

        # HTML的 links属性 可以快速获取到页面中 a标签中的href属性
        urls = html.links
        # pprint(urls)

        # HTML的 absolute_links属性 可以快速获取到页面中 a标签中的href属性,并返回绝对url地址

        absolute_urls = html.absolute_links
        pprint(absolute_urls)

    # 清洗数据(提取数据)
    def get_data_by_xpath(self):
        """使用xpath获取数据"""
        html = self.get_response(self.start_url)
        a_list = html.xpath('//table//div/a')
        # pprint(a_list)

        # 提取它的标题和url
        movies_info = dict()
        for a in a_list:
            title = a.text  # 获取标题(文本)
            # print(title)
            movie_url = a.attrs.get('href')  # 使用 attrs 来解析element元素,并获得一个字典
            # print(movie_url)
            # print('-----')
            movies_info[title] = movie_url

        pprint(movies_info)

    # 清洗数据(提取数据)
    def get_data_by_css(self):
        """使用css获取数据"""
        html = self.get_response(self.start_url)
        a_list = html.find('tr[class="item"] div a')  # 参考 css选择器 语法
        # pprint(a_list)

        # 提取它的标题和url
        movies_info = dict()
        for a in a_list:
            title = a.text  # 获取标题(文本)
            # print(title)
            movie_url = a.attrs.get('href')  # 使用 attrs 来解析element元素,并获得一个字典
            # print(movie_url)
            # print('-----')
            movies_info[title] = movie_url

        pprint(movies_info)

    # 清洗数据(提取数据)
    def get_data_by_re(self):
        """使用css获取数据"""
        html = self.get_response(self.start_url)

        # search() 获取第一条匹配的数据
        # first_url = html.search('a href="{}"')  # 参数可以参考正则,获取第一条匹配的数据
        # pprint(first_url)

        # search_all() 获取所有满足条件的数据列表
        # url_list = html.search_all('a h{}f="{}"')
        url_list = html.search_all('a h{title}f="{url}"')  # 对取值方式进行命名,返回一个列表

        # pprint(url_list)
        #
        # 提取数据
        for url in url_list:
            print(url)
            print(url['title'])  # 使用 result[name] 进行取值
            print(url['url'])
            # print(url[0])
            # print(url[1])
            print('----------')

    # HTML类
    def use_HTML(self):
        """使用HTML模块处理文档"""
        html_str = '<a class="nbg" href="https://movie.douban.com/subject/3099221/" title="活死人军团">'
        html = HTML(html=html_str)

        # links
        print(html.links)

        # search()
        print(html.search('href="{}"'))

    # 加载JS页面
    def load_js(self):
        html = self.get_response(self.js_url)

        # 使用一个 render()方法 来加载js(实际上使用这个pyppeteer)
        # html.render(wait=3)  # js加载
        print(html.html)

    async def send_requests_ues_async(self, url):
        """发送异步请求"""

        """获取响应,并返回requests_html中的HTML对象"""
        r = await self.aSession.get(url, headers=self.headers)
        # print(r)

        return r.html

    def get_response_by_async(self):
        url_list = [
            'https://www.baidu.com',
            'https://www.qq.com',
            'https://www.163.com',
        ]
        tasks = [lambda url=url: self.send_requests_ues_async(url) for url in url_list]
        ret = self.aSession.run(*tasks)  # 返回的是一个HTML对象列表
        # print(ret)
        # print(ret[0].html)
        for html in ret:
            print(html)

    async def load_js_use_async(self, url):
        """异步加载js"""
        html = await self.send_requests_ues_async(url)

        # 异步加载js
        await html.arender()

        return html

    def get_js_by_async(self):
        # ret = self.aSession.run(self.load_js_use_async)
        #
        # print(ret[0].html)

        url_list = [
            'https://www.baidu.com',
            'https://www.qq.com',
            'https://www.163.com',
        ]
        tasks = [lambda url=url: self.load_js_use_async(url) for url in url_list]
        ret = self.aSession.run(*tasks)  # 返回的是一个HTML对象列表
        # print(ret)
        # print(ret[0].html)
        for html in ret:
            print(html)


if __name__ == '__main__':
    test = DouBanTest()
    # test.get_data_by_xpath()
    # test.get_data_by_css()
    # test.fast_get_urls()
    # test.get_data_by_re()
    # test.use_HTML()
    # test.load_js()
    # test.get_response_by_async()
    test.get_js_by_async()

【本文由 "XiaoqiangClub" 发布,2021年6月17日】

所以放着《信号》迟迟没有安利,是因为这个剧的片源一直不稳定,这么紧凑烧脑欲罢不能的神剧,追到一半后面的资源看不了了的那种煎熬感,简直是抓心挠肝。

现在腾讯视频居然火速出了高质量正版了,终于是安利的最佳时刻了!!

友情提示:对《信号》来说,任何不一口气从头追到尾的看剧方式都是耍!流!氓!

(所以我们周五晚上才发这个,周末刷起来吧,hiahia)

《信号》引起我的注意的时候还只有一千多人打分,现在评价人数翻了十倍,分数一直坚挺保持在9.2,领先同期的《太阳的后裔》一个身位都不止。

又是一部看上去没什么大熟脸明星卡司,但是一但陷进去就无法挣脱的剧集,三大主演李帝勋、金惠秀、赵震雄都是演技派,我不会告诉你现在最右边的微胖沧桑大叔是我的梦中情人:

前有1988的一众丑男俘获万千少女心,后有信号里脸输配角一万倍的两大糙汉靠人设帅炸全宇宙,tvN你这么肆意操控我们的审美是不是很爽?!

《信号》的好看,很难用一两句话就说清楚。

虽然就是一部16集每集1小时左右的正常体量的韩剧而已,但是相比以往几乎所有在中国大红过的韩剧来说,它都丰富得多——形式感上有刑侦、悬疑、穿越;大格局包含了个人选择、家国命运、蝴蝶效应;感情上有爱情、亲情、对小人物的悲悯......

一部剧包含这么多元素不难,难的是随着剧情的铺垫强化,每一部分都渐入佳境,完成得很圆满:用了平行时空的设定但是没有明显的烂尾和bug,出场人物很多但是每个都立体丰满。16集看下来几乎没有一个废镜头,没有一处闲笔,每一集都是电影级别的质感。

唯一的缺点是第一集的前半个小时有点难进入,看起来不明就里,实在是因为编剧脑洞太大,开篇要交代的东西太多。

但是请答应我,一定要坚持住!

熬过这半小时,看懂了基本设定,你会被一股神秘力量带领着一集一集刷下去根本停不下来!而且开篇的每一个细节都要看仔细,看到后面会无数次想用小岳岳脸惊呼,我的天呐,原来前面早有暗示!

那种跟着编剧把记忆里星星点点的小怀疑一点点串联成一张网,在某个瞬间一下想通谜底的愉悦感,酣畅淋漓。

为了能方便说清楚《信号》好看在哪,我要把《信号》拆解成三个部分:

首先是破案。

《信号》最主要的一条线索,是年轻刑警朴海英捡到一个对讲机,从而和十多年前的前辈李材韩开始跨越时空的联系,两个人联手一起解决多年来悬而未决的案件。

这些案件每个都不简单。

比如说开篇引入的「金允贞诱拐案」:

朴海英小时候无意中目睹了同学金允贞被一个打扮艳丽的女人诱拐。很快这件涉及女学生的绑架案变成全社会的焦点,所有已知的证据都指向一个年轻男子,幼小的朴海英到警察局提供线索,但是一个小屁孩说的话根本没人在意。

因为警察被高智商罪犯戏耍,追查方向一开始就错了,「金允贞诱拐案」变成一桩悬案,直接悬了15年。

眼看诉讼时效还剩下三天,警方显然依旧没有(也怕麻烦不太想有)什么进展。

15年后,朴海英警校毕业,但是因为对警察的不信任,变成了一个利用刑侦能力追踪明星卖绯闻的混子。在一次调查明星被警察盯上带回警局调查的时候,他在警察局门口意外捡到一个没有电池的老式对讲机。

对讲机里短暂的信号,告诉了他关于「金允贞诱拐案」的一个关键线索,勾起了他十多年前的回忆。

他利用这个线索和自己强大的心理分析能力,很快锁定了真正的犯罪嫌疑的人特征,但是这时候距离「金允贞诱拐案」的诉讼时效中止,已经只剩下一个半小时。

罪犯通过新闻知道了警察追查的进展,但是心理极度自信的她决定继续戏耍警察——毕竟一个半小时之后,诉讼时效一过,就是知道她就是真凶,也没有人能动她一分一毫了。

真正紧张的地方从这里开始,这一个半小时简直过得比一年还漫长:

知道了犯罪分子的特征,但是被她误导追查了错误的人→→意识到被误导之后,真正的罪犯已经藏身→→找到她的藏身地点把她羁押,又没等到化验结果出来用证据盖章她就是罪犯→→试图在最后几分钟用心理战攻破她的防线让她认罪,但是她偏偏软硬不吃比警察想得更强大。

还剩几分钟了啊!

审讯室外面,是金允贞母亲苍老的脸:

15年来她只能每天站在路口举个牌子,呼吁大家不要忘了她女儿。

是韩国全社会对15年毫无进展的案件的关注。

是来自警察局领导的仇恨脸:马上就要过诉讼时效的案子让它安静过去就行了干嘛要闹出这么大的幺蛾子打我的脸!!!

千钧一发,按照以往我们熟悉的“最后一分钟营救”的经典套路,警察总是要在时间耗尽前最后一秒钟把罪犯绳之以法的,但这次并没有——

警察败了,束手无策。

编剧就是要观众和内心有责任感的主人公一起承受这种挫败感。只有这样,大家才能对「诉讼时效」制度给被害人家属带来的伤害有那么几分感同身受。

这正是《信号》的格局所在。

当然这还不是这个案件的最终结果,后面还有反转,我就不剧透了。

韩国的影视剧多次对「诉讼时效」制度是否合理做出过探讨。《信号》这次重提这个话题,也有特别的意义——在真实的韩国社会,原本杀人罪的诉讼时效是15年,2007年延长为25年。2015年7月24日,韩国国会通过刑事诉讼法修正案,正式废除了杀人罪的公诉时效。

一个又一个电影电视剧不遗余力参与社会议题,引起民众的关心和思考,积累起舆论的力量就可以改变国家。那种和主角一起经历一场高潮迭起绝处逢生的侦破过程,最后改变了法律制的体验,真的好燃!

接下来《信号》里每一个案件都无一例外有社会原型,并且现实意义被挖掘的越来越深。

京畿南部连环杀人案的原型是华城连环杀人案,在现实里至今是悬案。电影《杀人回忆》和tvN早先的电视剧《岬童夷》都改编自这个案件。《信号》是tvn第二次利用这个题材——

1986年至1991年间,韩国京畿道华城市太安镇一带,有10名女性依次被用残忍的手法杀害,杀人犯始终未被捕,最终成为未解决的杀人事件。

这起案子是韩国人心中的一根刺,杀人手法恶劣,投入警力众多,连犯罪者的画像都有,但就是抓不到人。这根刺不断被翻出来演绎,一次又一次提醒国人正义还没有来到,我们还没有放弃。

如果说前两个案子还主要集中在对社会制度的讨论,那么后面这几个就已经开始不遗余力地对公务阶层开黑了。

第三个案子申汝珍绑架案,犯罪者和被绑架的女生都是一次大桥坍塌事故的受害者。这个事故的原型是圣水大桥坍塌事件——一座刚建好的大桥因为施工腐败轰然倒塌。

《信号》里,坍塌事故有两个受害女学生,一个因为家里的权势得救,另一个只能在父亲的呼喊声里死去。

在这个案子里,镜头带过一下大桥坍塌事故的纪念碑,写着永远铭记遇难者:

讽刺得是,就在这座纪念碑前,15年过去,两个受害者家庭依旧因为当初谁应该获救而纠缠,衍生出绑架案甚至还有人因此丧命。

对受害者来说,家人去世了就是去世了,悲剧从来没有过去。但是对于参与贪腐的官员和生意人,一块纪念碑就足以遮掩一切。

看到这儿,我对《信号》针砭时弊的尺度已经深深拜服了。

接下来的大盗案件、仁州女高中生案件无一例外涉及权贵阶层和警察系统互相勾结,黑幕深不见底。

而且,申汝珍绑架案的犯罪者是大盗案件的受害者,仁州女高中生案件更是把所有主角全部串联在了一起。

一环一环紧紧相扣,因果相关,16集连着看下来没有一丝喘息的时间。

------------------

接下来说平行时空的设定。

《信号》紧凑的悬念,一部分来自于涉及的案件本身之复杂,另一部分是靠对讲机实现的跨越时空的联系。

这个设定已经不新鲜了,美剧、港剧都有先例。

《信号》好在没有让这个对讲机成为两个主角的外挂,从此所向披靡,而是让它带来很多祸患:

身处过去的李材韩依靠几十年后的信息源,改变着过去,但是过去被改变,现在也随之改变。这就像潘多拉的魔盒,一旦开始,没人知道会发生什么。

在京畿南部连环杀人案里,他们合力救下了一个被害者,但是这个举动15年后却造成另外一个无辜的人被杀死。所以利用对讲机救人是对是错?

即便连通古今,李材韩和朴海英都不是全知,朴海英被误导提供给李材韩错误的信息,造成无辜的人被冤枉,15年后酿成了更大的惨剧。谁该为这样的惨剧负责?

所以他们俩都曾经动摇过,一度断了联系。

但是最终,还是选择直面问题,联手对抗。

因为只有坚决对抗到绊倒黑幕源头的人,把真正的错误纠正了,才能彻底改变过去,继而改变未来。

对讲机的存在,也一度把李材韩推到悲剧人物的境地。

查案查到最后,朴海英知道李材韩会在查案过程里死去。但就是这次死前,他联通了和朴海英联络的对讲机,给朴海英提供了第一个线索。

朴海英该阻止李材韩,保护他不被杀死吗?

如果阻止了过去里的他死去,现在的他就能保全吗?

他查了一半的案子怎么办,就此放弃了吗?

这些悬念和两难的抉择推动剧情,在两个男主角的关系之间形成巨大的张力。

------------------

至于感情线,曾经被《请回答1988》的触动人,就一定会感受到《信号》的用心。

韩剧编剧的可怕之处在于,对于人性的细节的洞察。给每个人物,哪怕是支线里的小人物,都安排了很多前因后果的细节,慢慢铺陈,拼凑成一个个立体又可爱的普通人,一点点击中你。

比如硬汉刑警李材韩,他不是高大全的英雄,他也会哭,也会怀疑,有很多时候无能为力,看着自己的初恋女友在自己面前死去,明知道罪犯是谁又没法抓捕......

但是他永远有正义感——真正的正义感,不是无知无畏,是明知道自己内心也有恐惧,知道自己可能神仙危险,但是依然选择忠于内心的信念:

有同理心,每个受害者,对他来说都不是几张照片几个关键词,而是一个个活生生的人:

不放弃,哪怕用一己之力对抗全世界,也不放弃:

就是这么一个平凡到就在你我身边的糙汉,但谁又能说他不是英雄呢?每次他孤身一人出发去查案的时候,虽然就穿个破夹克邋邋遢遢的,但是正义和勇气的光环让他帅炸了!

李材韩的初恋女友是一个案件的受害者,受害之前,买了两张电影票本打算邀请李材韩一起看。

在初恋女友遇害之后,李材韩独自一个人来看电影,一个喜剧片,只有他身边的座位空着,周围全是笑声,没人懂他为什么哭成傻逼:

过了很多年之后,暗恋他的女刑警车秀贤在圣诞节请他看电影,他笑笑说:“我从来不看电影的。”

天哪!这云淡风轻的一句话,对观众来说简直是暴击!他从来没有放下过心里的伤痛,一个看起来不解风情的硬汉心里那点柔情,多么动人啊!

还有女一号车秀贤,一路从一个什么都不知道的傻妹:

眼神里都是纯真:

李材韩受伤,女汉子车秀贤在救护车上笨拙地哭着和李材韩表白,看得我又哭又笑,少女心炸裂:

后来他进化成干练的女刑警队长,一个人扛下所有压力,所谓爱一个人就是把自己活成他,这时候的车秀贤,已经是另一个李材韩。

追寻李材韩踪迹的十五年,没人知道她内心经历了多少失望、难过、寂寞,直到发现李材韩的尸骨,才终于哭出来:

这里要表白饰演车秀贤的金惠秀,她已经46岁了,演出女主角二十多岁的少女眼神依然毫无违和感,不愧是韩国顶级电影咖。

之前提到过每个配角都比两个男主角帅不是瞎说,有图为证

《信号》里的杀人犯长这样:

跋扈富二代长这样:

男主角被人冤枉入狱的哥哥长这样:

另外还有满嘴牢骚关键时刻觉不掉链子的逗逼同事:

亦正亦邪背负着一身秘密,最后变成关键性线索人物的科长:

每个人物身上都背负着好几重反转,再说下去就没完了,所有悬念等你看剧的时候慢慢发现!

总之,《信号》刑侦线、平行时空线、感情线,这三条线交织,看片体验就是:紧张、害怕、搞笑又感动。

同样的题材,给美剧可能拍成《24小时》,给港剧会拍成《隔世追凶》,国产剧这不能拍那拍不出来的,最后变成警察们谈恋爱,韩国人就综合各家之长,既有美剧的多线叙事,又有港剧的职场氛围,还不失韩剧本身的人情味,拍出一个可看性、深度、情感都兼顾得很好的剧。

当《信号》以口碑逆袭,在剧迷内部造成轰动效应之后,腾讯视频立刻就跟进买了正版全集,足见其实力。

如果说《太阳的后裔》还只是偶像剧领域的小超越,《信号》就是从创作环境到编剧能力、演员表演水准、对待观众的态度的全面碾压。

在整个影视产业,我们都被甩得太远了。

正版全集《信号》观看传送门

http://film.qq.com/cover/v/vkf8hhfj7uunkg6.html#rd