beautifulsoup网页爬虫解析_Python爬虫快速入门,静态网页爬取

在开始之前,请确保你的电脑上已经安装好了BeautifulSoup库,可以通过在命令行中输入pip install beautifulsoup4来进行安装。

一、数据解析

在爬取之前,我们需要检测下响应状态码是否为200,如果请求失败,我们将爬取不到任何数据:

import requestsre = requests.get('https://book.douban.com/top250')if re.status_code == 200:    print('请求成功!')else:    print('请求失败!响应状态码为{}'.format(re.status_code))

响应状态码为418,我们请求失败了,这是为什么呢?因为豆瓣有反爬虫机制,我们无法通过直接请求服务器来爬取数据,必须在发起请求之前将自己伪装起来。

1.1 反爬虫

反爬虫是网站限制爬虫的一种策略。它并不是禁止爬虫(完全禁止爬虫几乎不可能,也可能误伤正常用户),而是限制爬虫,让爬虫在网站可接受的范围内爬取数据,不至于导致网站瘫痪无法运行。常见的反爬虫方式有判别身份IP限制两种,这里我们先介绍前者,后者稍后再提及。

有些网站在识别出爬虫后,会拒绝爬虫进行访问,比如之前提到的豆瓣。那我们怎样做才能不被识别出来呢?在此之前,我们先尝试一下直接爬取:

import requestsre = requests.get('https://book.douban.com/top250')print(re.text)

结果是什么都没有输出,因为豆瓣将我们的爬虫识别了出来并拒绝提供内容。你可能会有疑问,爬虫不是模拟浏览器访问网站、获取网页源代码的吗?为什么就被识别出来了呢?事实上,无论是浏览器还是爬虫,访问网站时都会带上一些信息用于身份识别,而这些信息都被存储在一个叫请求头(request headers)的地方。

服务器会通过请求头里的信息来判别访问者的身份。请求头里的字段有很多,我们暂时只需了解user-agent(用户代理)即可。user-agent里包含了操作系统、浏览器类型、版本等信息,通过修改它我们就能成功地伪装成浏览器并爬取我们想要的数据。

那么如何找到user-agent呢?操作步骤如下:

  1. 首先按F12(或Fn+F12),然后单击上方的Network标签。
  2. 此时打开https://book.douban.com/top250,在Name一列中找到top250并单击。
  3. 在右边的Headers中找到Request Headers,User-Agent就在其中。

选中后将其复制下来,我的浏览器的User-Agent是Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36,而requests默认的User-Agent是python-requests/2.24.0。默认的User-Agent和在头上贴着“我是爬虫”的纸条没有什么区别,很容易被服务器识别出来。因此我们需要修改请求头里的user-agent字段内容,将爬虫伪装成浏览器。

我们只需定义一个字典(请求头字段作为键,字段内容作为值)传递给headers参数即可,方法如下:

import requestsheaders = {  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'}re = requests.get('https://book.douban.com/top250', headers=headers)print(re.text)

这样就能正常输出内容了(结果太长这里不展示)。除了user-agent之外的其他请求头字段也能以同样的方式添加进去,但大部分情况下我们只需要添加user-agent字段即可。当我们加了user-agent字段还是无法获取到数据时,说明该网站还通过别的信息来验证身份,我们可以将请求头里的字段都添加进去再尝试。

1.2 BeautifulSoup 对象

接下来我们将网页源代码解析成BeautifulSoup对象:

import requestsfrom bs4 import BeautifulSoupheaders = {  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'}re = requests.get('https://book.douban.com/top250', headers=headers)soup = BeautifulSoup(re.text, 'html.parser')

需要注意的是,创建BeautifulSoup对象时需要传入两个参数,第一个参数是要解析的HTML文本,即网站源代码的字符串形式re.text。第二个参数是解析HTML的解析器,html.parser是Python中内置的解析器,较为简单方便。

接下来我们分别打印soup和re.text,观察其内容有无区别:

import requestsfrom bs4 import BeautifulSoupheaders = {  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'}re = requests.get('https://book.douban.com/top250', headers=headers)soup = BeautifulSoup(re.text, 'html.parser')print(soup)print(re.text)

仔细观察后会发现两次打印的内容完全一样!既然都一样,我们何苦费这么大力将网页源代码解析成BeautifulSoup对象呢?为什么不直接打印re.text呢?

其实,它们只是看上去一样,实际上却属于不同种类。现在尝试用type()函数将re.text和BeautifulSoup对象的类型打印出来对比一下:

import requestsfrom bs4 import BeautifulSoupheaders = {  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'}re = requests.get('https://book.douban.com/top250', headers=headers)soup = BeautifulSoup(re.text, 'html.parser')print(type(re.text))soup = BeautifulSoup(re.text, 'html.parser')print(type(soup))

通过输出结果可以看出,re.text的类型是字符串,而soup的类型是BeautifulSoup对象,它俩是完全不同的东西。相比字符串,BeautifulSoup对象里有很多强大的方法和属性。通过这些方法和属性,我们就能方便快捷地提取出我们所需要的数据。

二、数据提取

BeautifulSoup对象里的方法和属性有很多,我们只学习其中最常用的一些,这些足以应付大多数场景。等你真正的入门后,可以自行学习那些更高阶的知识去解决更复杂的问题。

2.1 find()与find_all()

BeautifulSoup对象里的find()和find_all()是我们提取数据最常用的两个方法。借助它们,我们可以过滤掉HTML页面里的无用数据,轻松地找到我们需要的数据。

我们先来看一下find()和find_all()的作用和区别:

方法作用find()返回符合条件的首个数据find_all()返回符合条件的所有数据

我们通过一个例子进一步熟悉这两个方法,假设我们获取到的网页源代码如下:

登录/注册

豆瓣读书 Top 250

豆瓣书店
红楼梦
百年孤独
白夜行

接下来分别使用find()与find_all(),观察输出结果的差异:

print(soup.find('a'))print(soup.find_all('a'))

其中,使用find()方法输出的结果为:

登录/注册

而使用find_all()方法输出的结果为:

[登录/注册,豆瓣书店,红楼梦,百年孤独,白夜行]

可以看到,find()方法返回了第一个a标签,而find_all()方法则返回了所有的a标签。它俩的用法基本一样,都是传入HTML标签名称,返回符合该HTML标签的数据。区别是find()方法只返回第一个符合条件的标签,而find_all()方法返回所有符合条件的标签列表

除了传入标签名称外,这两个方法还支持传入属性进行筛选,返回符合条件的数据。例如:

soup.find('div', id='a') # 查找id='a'的div标签soup.find_all('var', class_='b') # 查找所有class='b'的var标签soup.find('button', id='c', class_='d') # 查找id='c'且class='d'的button标签

注:因为class是Python中定义类的关键字,因此用class_表示HTML中的class。

2.2 Tag对象

BeautifulSoup将HTML中的元素封装成了Tag对象。和BeautifulSoup对象一样,Tag对象里也有find()和find_all()方法。因此,我们可以不断地调用这两个方法,一层一层地找到我们需要的数据。依然使用之前的例子:

登录/注册

豆瓣读书 Top 250

豆瓣书店
红楼梦
百年孤独
白夜行

我们可以看到,书名在a标签中。但如果直接使用soup.find_all(‘a’)的话,第二行的“登录/注册”和第五行的“豆瓣书店”也会被获取到,因此我们需要将这些无效数据过滤掉。

深入思考一下不难发现,书名在class="item"的div标签里的a标签内。我们只要先找到所有class="item"的div标签,然后再找到其中的a标签即可,因此我们可以像下面这样来获取书名的数据:

items = soup.find_all('div', class_='item')for item in items:print(item.find('a'))

输出结果:

红楼梦百年孤独白夜行

这样,我们就找到了所有书名的数据。但此时返回的还是Tag对象。如果我们只想要书名和对应的链接呢?这就用到了Tag对象的text属性和HTML属性名取值。

items = soup.find_all('div', class_='item')for item in items:    tag = item.find('a')    name = tag.text    link = tag['href']    print(name, link)

输出结果:

红楼梦 https://book.douban.com/subject/1007305/百年孤独 https://book.douban.com/subject/6082808/白夜行 https://book.douban.com/subject/10554308/

我们通过Tag对象的text属性拿到了a标签里的文字内容,即红楼梦等。然后我们通过和字典取值一样的方式,将HTML属性名作为键,得到了对应属性的值。这里是以href属性为例,其他的HTML属性也同样可以。

Tag对象的常用属性和方法总结如下:

属性/方法作用tag.find()返回符合条件的首个数据tag.find_all()返回符合条件的所有数据tag.text获取标签的文本内容tag[‘属性名’]获取标签属性的值

我们通过多次调用find()或find_all()方法一层层地找到了我们需要的数据。那有没有什么方法可以直接就找到我们需要的数据,而不用多次查找吗?

答案是肯定的,这就需要用到CSS选择器了。

2.3 CSS选择器

在CSS选择器中,#代表id,.代表class。比如:#a表示id=‘a’的所有元素,.b表示class=‘b’的所有元素。当然,我们也可以直接通过标签名选择对应的元素,例如:a表示所有的a元素。

事实上,它们还可以组合在一起,选择同时符合条件的元素,比如:a#b表示所有id=‘b’的a元素,d.c 表示所有class=‘c’的d元素,#b.c 表示所有 id=‘b’ 且 class=‘c’ 的元素,.c.f 表示所有class同时为c和f的元素。

需要注意的是,选择同时符合条件的元素,选择器之间不能有空格,如果写成.c .f就是另一个意思了。这是因为,当两个选择器之间加了空格,表示子元素选择。还是以.c .f为例,它表示选择所有class=‘c’的元素里面class=‘f’的元素,即嵌套在class=‘c’的元素里面class=‘f’的元素。这个嵌套可以是任意层级的,只要在里面就行,不要求直接嵌套在第一层。如果只需要直接嵌套在第一层符合条件的元素,可以用>分隔,例如:.c > .f。

我们来通过一个例子了解一下CSS选择器的用法:

from bs4 import BeautifulSouphtml = '''

红楼梦

白夜行

'''soup = BeautifulSoup(html, 'html.parser')print(soup.select('.item.book'))print(soup.select('.item .book'))print(soup.select('.item > .book'))

输出结果:

[][

红楼梦

,

白夜行

][

红楼梦

]

BeautifulSoup对象有一个select()方法,我们将CSS 选择器传进去即可直接找到我们需要的元素。之前查找在class="item"的div标签里的a标签的代码就可以这样写:

items = soup.select('div.item a')for item in items:    name = item.text    link = item['href']    print(name, link)

可以看到,我们一次性就将所有符合条件的a元素找了出来,同样的功能,代码变得更加简洁了。

三、单个网页爬取

学习到这里,现在你应该可以独自完成爬取豆瓣图书的任务了,豆瓣图书Top250地址:https://book.douban.com/top250。

接下来我会给出具体的思路,不过建议你先尝试独立完成这个任务

首先,此前我们已经提到过,豆瓣是禁止反爬虫的,我们通过修改User-Agent伪装成浏览器成功“骗过”了豆瓣的识别:

import requestsfrom bs4 import BeautifulSoupheaders = {  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'}re = requests.get('https://book.douban.com/top250', headers=headers)soup = BeautifulSoup(re.text, 'html.parser')

接下来,我们需要利用CSS选择器将我们所需要的数据存储在items变量中,但是,如何找到图书名称所在的标签呢?

其实很简单,我们先打开https://book.douban.com/top250,右键单击红楼梦>检查,如下图所示:

ad64d941a508a223ca5400c7c083e54a.png


不难看出,书名是a标签内属性title的值,且这个a标签位于class=“pl2”的div标签

在知道了书名的“坐标”后,我们就可以使用CSS选择器啦:

items = soup.select('div.pl2 a')1

此时items变量实际上是一个由Tag对象组成的列表,我们可以通过循环打印书名和对应的链接:

for item in items:    name = item['title']    link = item['href']    print(name, link)1234

完整的代码如下:

import requestsfrom bs4 import BeautifulSoupheaders = {  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'}re = requests.get('https://book.douban.com/top250', headers=headers)soup = BeautifulSoup(re.text, 'html.parser')items = soup.select('div.pl2 a')for item in items:    name = item['title']    link = item['href']    print(name, link)1234567891011121314

爬取到的结果:

红楼梦 https://book.douban.com/subject/1007305/活着 https://book.douban.com/subject/4913064/1984 https://book.douban.com/subject/4820710/百年孤独 https://book.douban.com/subject/6082808/飘 https://book.douban.com/subject/1068920/三体全集 https://book.douban.com/subject/6518605/三国演义(全二册) https://book.douban.com/subject/1019568/白夜行 https://book.douban.com/subject/10554308/房思琪的初恋乐园 https://book.douban.com/subject/27614904/福尔摩斯探案全集(上中下) https://book.douban.com/subject/1040211/动物农场 https://book.douban.com/subject/2035179/小王子 https://book.douban.com/subject/1084336/天龙八部 https://book.douban.com/subject/1255625/撒哈拉的故事 https://book.douban.com/subject/1060068/安徒生童话故事集 https://book.douban.com/subject/1046209/哈利•波特 https://book.douban.com/subject/24531956/人类简史 https://book.douban.com/subject/25985021/沉默的大多数 https://book.douban.com/subject/1054685/围城 https://book.douban.com/subject/1008145/平凡的世界(全三部) https://book.douban.com/subject/1200840/杀死一只知更鸟 https://book.douban.com/subject/6781808/局外人 https://book.douban.com/subject/4908885/明朝那些事儿(1-9) https://book.douban.com/subject/3674537/霍乱时期的爱情 https://book.douban.com/subject/10594787/笑傲江湖(全四册) https://book.douban.com/subject/1002299/12345678910111213141516171819202122232425

仔细观察不难发现,上述所说的a标签内的文本内容只有书名,因此除了使用item[‘title’]外,我们还可以使用item.text:

for item in items:    name = item.text    link = item['href']    print(name, link)1234

输出结果(结果太长这里仅展示前面的一部分):

                红楼梦               https://book.douban.com/subject/1007305/                活着               https://book.douban.com/subject/4913064/                1984               https://book.douban.com/subject/4820710/                百年孤独               https://book.douban.com/subject/6082808/1234567891011121314151617181920

为什么使用item.text就会出现一些奇怪的换行呢?

我们知道,item.text是获取标签内的所有文本内容,空格,换行符等都会获取,我们再来看一下之前的a标签:

4100365f54137aa1620a859d1397a45e.png


显然a标签里存在空格和换行符,因此如果想使用item.text输出结果,我们必须使用join()方法去掉这些多余的空格和换行符:

for item in items:    name = ''.join(item.text.split())    link = item['href']    print(name, link)1234

这样结果就可以正常显示啦。

四、爬取所有Top250图书

可能你已经发现了,我们之前爬取的图书仅仅是第一页的,并不是所有的Top250图书,那么如何爬取所有的呢?

我们进入第二页后,可以看到网址变成了https://book.douban.com/top250?start=25,相比原来多了个?start=25。

我们再进入第一页,会发现网址变成了https://book.douban.com/top250?start=0。之后,再进入最后一页,网址变成了https://book.douban.com/top250?start=225。

我想你应该已经找到了其中的规律。

很显然,"start="后面的数字总是以步长25进行递增,第一页此数字是0,第十页此数字是225,这让我们联想到了循环。

我们先把之前爬取图书的代码封装成一个函数:

def spider(url):    headers = {      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'    }    re = requests.get(url, headers=headers)    soup = BeautifulSoup(re.text, 'html.parser')    items = soup.select('div.pl2 a')    for item in items:        name = item['title']        link = item['href']        print(name, link)1234567891011

豆瓣图书Top250共有十页,我们根据之前找出来的规律,利用循环生成这十个网页地址:

for i in range(0, 250, 25):    douban_book = 'https://book.douban.com/top250?start=%s' % str(i)12

之后,将它们组装在一起,我们就可以爬取所有图书了:

import requestsfrom bs4 import BeautifulSoupdef spider(url):    headers = {      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'    }    re = requests.get(url, headers=headers)    soup = BeautifulSoup(re.text, 'html.parser')    items = soup.select('div.pl2 a')    for item in items:        name = item['title']        link = item['href']        print(name, link)for i in range(0, 250, 25):    douban_book = 'https://book.douban.com/top250?start=%s' % str(i)    spider(douban_book)1234567891011121314151617181920

但考虑到输出结果太长,不方便在终端查看,我们可以将爬取到的结果写入文件:

import requestsfrom bs4 import BeautifulSoupdef spider(url, filename):    headers = {      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'    }    re = requests.get(url, headers=headers)    soup = BeautifulSoup(re.text, 'html.parser')    items = soup.select('div.pl2 a')    with open(filename, 'a', encoding=re.encoding) as f:        for item in items:            line = item['title'] + " " + item['href'] + ""            f.write(line)for i in range(0, 250, 25):    douban_book = 'https://book.douban.com/top250?start=%s' % str(i)    spider(douban_book, 'doubanTop250.txt')1234567891011121314151617181920

效果:

0f92ddf993f54f317bc14fbf3a75f5af.png

五、防BAN策略

爬虫在网页上爬取数据时如果不加任何限制会“高速”访问对方的服务器,如果访问太快容易导致被对方服务器封禁,因为正常人是不会在1秒内访问几十次甚至上百次网站的,这样就会导致我们在一段时间内无法访问这个网站。所以,如果你访问过于频繁,即使通过修改User-Agent伪装成浏览器,也还是会被识别出爬虫,并限制你的IP访问该网站。

那么如何防止自己被封禁呢?这里介绍两种策略,一种是降低自己的爬取速度,另一种是IP代理。

5.1 使用time.sleep()降低爬取速度

time.sleep(secs)函数推迟调用线程的运行,可通过参数secs(秒数)来进行设置。

我们先来看一个例子:

import timefor i in range(0, 10):    print(i)    time.sleep(1)12345

运行后,终端先是输出0,之后每隔1秒输出一个数字。倘若不加上time.sleep(1),那么这10个数字会在“一瞬间”打印出来。显然,time.sleep()延迟了打印这个操作。

利用这个特点,我们可以在之前爬取豆瓣图书Top250的代码中使用time.sleep(),以降低爬取速度,防止被封:

import requestsfrom bs4 import BeautifulSoupfrom time import sleep as pausedef spider(url, filename):    headers = {      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'    }    re = requests.get(url, headers=headers)    soup = BeautifulSoup(re.text, 'html.parser')    items = soup.select('div.pl2 a')    with open(filename, 'a', encoding=re.encoding) as f:        for item in items:            line = item['title'] + " " + item['href'] + ""            f.write(line)for i in range(0, 250, 25):    douban_book = 'https://book.douban.com/top250?start=%s' % str(i)    spider(douban_book, 'doubanTop250.txt')    pause(1)12345678910111213141516171819202122

这样我们就可以每隔1秒爬取一页,降低了访问频率。

5.2 IP代理

除了降低访问频率之外,我们也可以使用代理来解决IP限制的问题。代理的意思是通过别的IP访问网站。这样,在IP被封后我们可以换一个IP继续爬取数据,或者每次爬取数据时都换不同的IP,避免同一个IP访问的频率过高,这样就能快速地大规模爬取数据了。

如何使用代理呢?请看下例:

import requestsproxies = {  "http": "http://10.10.1.10:3128",  "https": "http://10.10.1.10:1080",}requests.get("http://example.org", proxies=proxies)12345678

和headers一样,我们同样需要定义一个字典,但传递的是proxies参数。我们需要将http和https这两种协议作为键,对应的IP代理作为值,最后将整个字典作为proxies参数传递给requests.get()方法即可。

注:IP代理有免费的和收费的,你可以自行在网上寻找。

在爬取大量数据时我们需要很多的IP用于切换。因此,我们需要建立一个IP 代理池(字典列表),每次从中随机选择一个传给proxies参数。

因此,使用IP代理并结合time.sleep()爬取豆瓣图书Top250再将其写入文件的完整代码如下:

import requestsfrom random import choicefrom bs4 import BeautifulSoup as BeSfrom time import sleep as pausedef spider(url, filename, proxies):    headers = {      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'    }    re = requests.get(url, proxies=proxies, headers=headers)    soup = BeS(re.text, 'html.parser')    items = soup.select('div.pl2 a')    with open(filename, 'a', encoding=re.encoding) as f:        for item in items:            f.write(item['title'] + " " + item['href'] + "")filename = 'doubanTop250.txt'pages = []proxies_list = []for i in range(0, 250, 25):    ip_1 = "http://10.10.1.1%s:3128" % str(i // 25)    ip_2 = "http://10.10.1.1%s:1080" % str(i // 25)    douban_book = 'https://book.douban.com/top250?start=%s' % str(i)    prox = {        "http": ip_1,        "https": ip_2,    }    pages.append(douban_book)    proxies_list.append(prox)for page in pages:    proxies = choice(proxies_list)    spider(page, filename, proxies)    pause(1)12345678910111213141516171819202122232425262728293031323334353637

上述代码的IP代理池中的IP代理不可用(IP地址是瞎写的),所以代码不会成功运行,这里仅仅是为了展示一个完整的结构。

有点长,需要完整项目代码的私信小编01

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488818.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android获取小程序音频时长,微信小程序获取音频时长与实时获取播放进度

首先在没有播放音频之前,居然拿不到总时长但是在播放之后也需要设置setTimeout来获取所以在监听音频播放进度更新事件中获取。顺便获取当前播放进度按照官方的写法audioPlayed: function () {myAudio.play()setTimeout(() > {myAudio.onTimeUpdate(() > {cons…

Shell awk文本处理,shell脚本编写

Shell awk文本处理,shell脚本编写 一:内容包含awk、变量、运算符、if多分支 <a>语法糖&#xff1a; awk [options] commands files option   -F  定义字段分隔符,默认的分隔符是连续的空格或制表符      使用option中的-F参数定义间隔符号      用$1,$2,$3…

当超级智能崛起时……

来源&#xff1a;资本实验室“大雷&#xff0c;你脑子没出啥毛病吧&#xff1f;”李春花轻声问道&#xff0c;眼睛里满是关切的神色。“喔&#xff0c;你放心&#xff0c;俺没事&#xff01;上次的事故之后&#xff0c;我的芯片和操作系统都已经升级到最新版本啦&#xff01;”…

小米小爱音箱Pro8安装app_小米小爱音箱HD获DXO评为第二!低音准确度很高

前几天&#xff0c;知名评测机构DXOMARK公布了用于测试无线音箱音质的新基准——DXOMARK Speaker。据了解&#xff0c;这个基准由百个测试汇集而成&#xff0c;该机构称这个基准为针对音箱产品唯一的科学评分。11月9日&#xff0c;该机构发文称&#xff0c;小米小爱音箱HD获得了…

Android自定义组合布局,Android 流式布局 + 自定义组合控件

自定义组合控件package yanjupeng.bawei.com.day09.two;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.widget.EditText;import android.widget.Lin…

freemark循环map_freemarker中循环map根据key值得value 报错

[#list uMap?keys as key]${uMap[key]}[/#list]Map uMap new HashMap();uMap.put(1,"zhangsan");uMap.put(2,"lisi");model.addAttribute("uMap", uMap);严重: Servlet.service() for servlet springMVC threw exceptionFreeMarker template e…

Lua的垃圾回收机制详解

Lua 是一种轻量级的编程语言&#xff0c;广泛用于嵌入到其他应用程序中&#xff0c;尤其是在游戏开发领域。Lua 的内存管理机制采用了自动垃圾收集&#xff08;Garbage Collection&#xff09;的方法。以下是Lua内存管理的一些关键方面&#xff1a; 垃圾收集原理概述 Lua 使用…

2020年AI怎么发展?听加州大学、谷歌、英伟达、IBM怎么说

来源&#xff1a;机器之心AI 领域最杰出的头脑如何总结 2019 年技术进展&#xff0c;又如何预测 2020 年发展趋势呢&#xff1f;本文介绍了 Soumith Chintala、Celeste Kidd、Jeff Dean 等人的观点。人工智能不是将要改变世界&#xff0c;而是正在改变世界。在新年以及新的十年…

python线程池官网-Python线程池下载txt

下次试试用scrapy模块 # codingutf-8 import requests import threadpool def download_file(i): """下载文件""" download_url f"https://www.txt2016.com/e/DownSys/xiazai/?classid1&pathid0&id{i}" file requests.get(…

select样式的重写

select {/*统一边框*/border: solid 1px #000;/*将默认的select选择框样式清除*/appearance:none;//这个样式就是清楚他的下拉按钮的默认样式-moz-appearance:none;-webkit-appearance:none;/*替换选择框的最右侧显示小箭头图片*/background: url("http://****.png")…

ip打包后如何加入 xilinx_科普!插上USB设备后电脑是怎么识别的呢?

欢迎FPGA工程师加入官方微信技术群每次当插上鼠标或者U盘的时候&#xff0c;电脑是怎么知道是什么设备的呢&#xff1f;这里用到的就是枚举了。枚举&#xff0c;其实就是让HOST认识这个USB涉笔&#xff0c;并且为该设备准备资源&#xff0c;建立好主机和设备之间的数据传递机制…

两院院士评选2019年中国、世界十大科技进展新闻揭晓

来源&#xff1a;科学网由中国科学院、中国工程院主办&#xff0c;中国科学院学部工作局、中国工程院办公厅、中国科学报社承办&#xff0c;中国科学院院士和中国工程院院士投票评选的2019年中国十大科技进展新闻、世界十大科技进展新闻&#xff0c;1月11日在京揭晓。此项年度评…

android炫酷叼ui,XUI: 一个简洁而优雅的Android原生UI框架,解放你的双手!

XUI一个简洁而又优雅的Android原生UI框架&#xff0c;解放你的双手&#xff01;还不赶紧点击使用说明文档&#xff0c;体验一下吧&#xff01;涵盖绝大部分的UI组件&#xff1a;TextView、Button、EditText、ImageView、Spinner、Picker、Dialog、PopupWindow、ProgressBar、Lo…

笔记本电脑麦克风在哪里_定制款MacBook Pro? 13.3 体验 “旧”时代的 One Pecie_笔记本电脑...

2020-11-11 13:19:377点赞18收藏18评论9月28日 - 11月12日&#xff0c;参与#双11购物攻略#征稿活动&#xff0c;赢取苹果全家桶8888元超级锦鲤大奖&#xff01;瓜分十万金币&#xff0c;值得买周边一次全攒齐&#xff01;品类、品牌、场景、价格&#xff0c;快来分享你的购物心…

android 拍照屏幕大小,Android Camera 找出屏幕的最佳尺寸大小

大家平时都会调用到Camera 这个API&#xff0c;在设置Camera.Paramera的参数的时候&#xff0c;有一个预览大小。也就是&#xff1a;setPreviewSize(int width, ing height)这个相机的大小不能随便设置&#xff0c;如果设置了不可接受的值&#xff0c;程序会崩溃掉。现在给大家…

Shell脚本-自动化部署反向代理、WEB、nfs

部署nginx反向代理三个web服务&#xff0c;调度算法使用加权轮询(由于物理原因只开启两台服务器) AutoNginxNfsService.sh #/bin/bash systemctl status nginx if(($?4))then yum install -y nginxif(($?0))then#echo Yes!systemctl start nginxif(($?0))thenecho "Con…

a76比a73强多少_arm的a73和a72同上10nm,谁强?

说到ARM A72和A73 就不得不说一个事&#xff0c;A73相比A72并不是一个简单的升级&#xff0c;A72和A73不是同一个团队做的。A73其实有点像当初的A17&#xff0c;整体微架构、流水线、宽度设计都与之类似。A73和A72相比没有保留A72的三发射&#xff0c;改用了双发射。ARM的宣传A…

杨振宁眼中的物理学之美

来源&#xff1a;EETOP本文是当代物理学大师杨振宁教授1997年1月17日在香港中华科学与社会协进会与香港中文大学主办的演讲会上的演讲词&#xff0c;讲题原为“科学工作有没有风格”。转载于香港《二十一世纪》杂志1997 年 4 月号&#xff0c;总第40期&#xff1b;也收入杨振宁…

wechat电脑版_【学术工具】如何快速、免费翻译英文材料?原创·WeChat公号:本硕博资讯...

★学术工具英文材料免费翻译如何快速、免费翻译英文材料&#xff1f;原创WeChat公号&#xff1a;本硕博资讯分享一些亲测可用的资源&#xff0c;仅用于学术交流。建议大家试着自己翻译&#xff0c;提升英语水平。版权声明&#xff1a;如有侵权问题请通过邮箱或者公众号后台私信…

float php 运算_系统的讲解 - PHP 浮点数高精度运算

概述记录下&#xff0c;工作中遇到的坑 ...关于 PHP 浮点数运算&#xff0c;特别是金融行业、电子商务订单管理、数据报表等相关业务&#xff0c;利用浮点数进行加减乘除时&#xff0c;稍不留神运算结果就会出现偏差&#xff0c;轻则损失几十万&#xff0c;重则会有信誉损失&am…