<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Selenium 是一個用於Web應用程式測試的工具。Selenium測試直接執行在瀏覽器中,就像真正的使用者在操作一樣。
1、Selenium Webdriver(也就是Selenium2,Selenium3)和Selenium RC(Selenium 1)一樣提供了web自動化的各種語言呼叫介面庫。相比Selenium RC,Selenium WebDriver的程式設計介面更加直觀易懂,也更加簡練。
但是和Selenium RC不同的是,Selenium Webdriver是通過各種瀏覽器的驅動(web driver)來驅動瀏覽器的,而不是通過注入JavaScript的方式。
我們的程式碼執行起來是一個程序,裡面呼叫Selenium WebDriver的庫和各個瀏覽器的驅動程序 進行互動,傳遞Selenium命令 給它們,並且獲取命令執行的結果,返回給我們的程式碼進行處理。
2、Selenium WebDriver目前包括兩個版本Selenium 2和Selenium 3。這兩個版本從開發程式碼呼叫介面上來看,幾乎沒什麼區別。區別在於庫的實現和web driver的實現。
Selenium2是Selenium組織幫各種瀏覽器寫web driver的,而Selenium 3裡面的web driver是由各個瀏覽器廠商(Apple,Google,Microsoft,Mozilla)自己提供的。所以Selenium 3的自動化效率更高,成功率也更高。
3、Selenium WebDriver 支援瀏覽器眾多:
利用它可以驅動瀏覽器執行特定的動作,如點選、下拉等操作,同時還可以獲取瀏覽器當前呈現的頁面的原始碼 ,做到可見即可爬。
所以Selenium現在被廣泛用於Python爬蟲。查了下資料,發現這個工具確實強大,最重要的是,C#也是可以呼叫的。
官方支援Java,C#,Python,Ruby,PHP,Perl,Javascript等語言
官方檔案(有C#範例):https://www.selenium.dev/documentation/en/
1、我們新建一個C#控制檯程式
2、使用Nuget搜尋以下依賴庫
需要參照的核心庫是Selenium.RC,Selenium.Support,Selenium.WebDriver
然後再需要參照瀏覽器驅動庫,這裡我以新版Edge瀏覽器為例,新版Edge使用方式跟Chrome是一樣的,程式包名稱為Selenium.WebDriver.MSEdgeDriver。
備註:也可以在微軟WebDriver官網下載Edge (Chromium)的webdriver,需要和當前瀏覽器版本一致。然後下載放置到專案可執行檔案的目錄。
如果使用Chrome:
先查下本機Chrome的版本
然後去Nuget搜尋Selenium.WebDriver.ChromeDriver進行下載安裝。
注意:webdriver版本只需要和當前瀏覽器主版本一致即可。
3、在Main函數中輸入以下程式碼
using OpenQA.Selenium; using OpenQA.Selenium.Edge; using System; using System.Windows.Forms; namespace WinForm2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { var service = EdgeDriverService.CreateDefaultService(@".", "msedgedriver.exe"); using (IWebDriver driver = new OpenQA.Selenium.Edge.EdgeDriver(service)) { driver.Navigate().GoToUrl("http://www.baidu.com"); //driver.Url = "http://www.baidu.com"是一樣的 var source = driver.PageSource; this.textBox1.Text = source; } } } }
如果是Chrome瀏覽器,可以這樣:
IWebDriver driver = new OpenQA.Selenium.Chrome.ChromeDriver(); driver.Navigate().GoToUrl("http://www.baidu.com");
執行,會彈出IE瀏覽器,網頁載入完成後,瀏覽器會自動關閉。控制檯輸入結果如下
這樣我們就可以輕鬆的獲取動態渲染頁面的原始碼。
常用的等待分為顯示等待WebDriverWait()、隱式等待ImplicitlyWait()、強制等待sleep()三種,下面我們就分別介紹一下這三種等待的區別
用到Timeouts物件。這個物件是用來對設定器進行一些設定的。
程式碼如下:
driver.Navigate().GoToUrl("http://www.baidu.com"); ITimeouts timeouts = driver.Manage().Timeouts(); //設定查詢元素最大超時時間為30秒 timeouts.ImplicitWait = new TimeSpan(0, 0, 30); //設定頁面操作最大超時時間為30秒 timeouts.PageLoad = new TimeSpan(0, 0, 30); //設定指令碼非同步最大超時時間為30秒 timeouts.AsynchronousJavaScript = new TimeSpan(0, 0, 30);
//等待頁面元素載入完成 //預設等待100秒 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(100)); //等待頁面上ID屬性值為submitButton的元素載入完成 IWebElement myElement = wait.Until((d) => { return d.FindElement(By.Id("submitButton")); });
通過FindElement()這個方法來查詢的。然後把引數傳遞過去。
driver.FindElement(By.Id ("kw")).SendKeys("搜尋鍵碼"); driver.FindElement(By.Id( "su")).Click();
其中By.id("su")就是定位引數,傳遞一個物件過去。有8種定位方式。
注意:其中PartialLinkText是模糊查詢。比如百度網頁中的關於 引數寫“關”就可以了,不用寫*這種符號。
//通過ID獲取元素 var byID = driver.FindElement(By.Id("cards")); //通過類名獲取元素by class name var byClassName = driver.FindElements(By.ClassName("menu")); // 通過標籤名獲取元素by tag name var byTagName = driver.FindElement(By.TagName("iframe")); // 通過名字獲取元素 var byName = driver.FindElement(By.Name("__VIEWSTATE")); // 通過連結文字獲取元素by linked text <a href="https://www.cnblogs.com/springsnow/p/%3C/span%3E%3Cspan%20style=" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" target="_blank">http://www.google.com</a><a href="https://www.cnblogs.com/springsnow/p/%3C/span%3E%3Cspan%20style=" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" target="_blank">">linkedtext</a>> var byLinkText = driver.FindElement(By.LinkText("linkedtext")); // 通過部分連結文字獲取元素by partial link text :<a href="https://www.cnblogs.com/springsnow/p/%3C/span%3E%3Cspan%20style=" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" target="_blank">http://www.google.com</a><a href="https://www.cnblogs.com/springsnow/p/%3C/span%3E%3Cspan%20style=" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" target="_blank">">linkedtext</a>> var byPartialLinkText = driver.FindElement(By.PartialLinkText("text")); //通過CSS選擇器獲取元素by css var byCss = driver.FindElement(By.CssSelector("#header .content .logo")); // 通過XPath來獲取元素(by xpath var byXPath = driver.FindElements(By.XPath("//div"));
各方法使用優先原則:
優先使用id,name,classname,link;次之使用CssSelector();最後使用Xpath();
因為Xpath()方法的效能和效率最低下。
1.Title:標題
Console.WriteLine(driver.Title);//輸出標題名
2.Url:連結
Console.WriteLine(driver.Url);//輸出連結
3.Text:元素的文字值
Console.WriteLine(web.Text);//輸出元素標記中文字的資訊
4.Selected勾選情況、TagName標記名標、Enabled編輯狀態、Displayed顯示狀態
5.GetAttribute()獲取標籤的屬性
var byIDAttributeText = byID.GetAttribute("id");
6.彈出對話方塊的處理
首先,要先了解三種對話方塊:Alert、Confirmation以及Prompt。測試網頁test.html:
<html> <head> <title>這是標題</title> </head> <body> <input type="button" onclick="alert('這是Alert');" value="Alert" /><br/> <input type="button" onclick="confirm('這是confirm');" value="confirm" /><br/> <input type="button" onclick="prompt('這是Prompt');" value="prompt" /><br/> </body> </html>
下面進行測試:
var service = EdgeDriverService.CreateDefaultService(@".", "msedgedriver.exe"); IWebDriver driver = new OpenQA.Selenium.Edge.EdgeDriver(service); driver.Navigate().GoToUrl("file:///C:/Users/bobin.yang/Source/Repos/WinForm2/bin/Debug/HTMLPage1.html"); IWebElement web = driver.FindElement(By.XPath("//input[1]")); web.Click(); WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,2)); //Wait for the alert to be displayed wait.Until(ExpectedConditions.AlertIsPresent()); Console.WriteLine(driver.SwitchTo().Alert().Text);//在接收訊息前輸出 System.Threading.Thread.Sleep(1000); driver.SwitchTo().Alert().Accept(); IWebElement web2 = driver.FindElement(By.XPath("//input[2]")); web2.Click(); WebDriverWait wait2 = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); wait2.Until(ExpectedConditions.AlertIsPresent()); Console.WriteLine(driver.SwitchTo().Alert().Text);//在接收訊息前輸出 System.Threading.Thread.Sleep(1000); driver.SwitchTo().Alert().Accept(); IWebElement web3 = driver.FindElement(By.XPath(@"html/body/input[3]")); web3.Click(); System.Threading.Thread.Sleep(1000); Console.WriteLine(driver.SwitchTo().Alert().Text);//在接收訊息前輸出 driver.SwitchTo().Alert().SendKeys("這是輸入的內容"); driver.SwitchTo().Alert().Accept();
主要是進行Click和SendKeys操作,如圖。其它的自己檢視定義就知道了。
driver.FindElement(By.Id("copyright")).Click();
Selenium中在指定的文字方塊中輸入指定的字串
//在文字方塊中輸入指定的字串sendkeys() Driver.FindElement(By.Id("tranAmtText")).SendKeys(「123456」);
driver.Navigate().GoToUrl("http://tieba.baidu.com/f/search/adv"); IList listOption = driver.FindElement(By.Name("sm")).FindElements(By.TagName("option")); string targetStr = "按相關性排序"; foreach (var option in listOption) { if (option.Text == targetStr) // if (option.GetAttribute("value").Equals(targetStr)) option.Click(); }
var jsReturnValue = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("jsfunname");
driver.Navigate().Forward(); driver.Navigate().Back();
Selenium中移動遊標到指定的元素上
//移動遊標到指定的元素上perform Actions action=new Actions(driver); action.MoveToElement(Find(By.XPath("//input[@id='submit' and @value='確定']"))).Perform();
var element = driver.FindElement(By.Name("source")); IWebElement target = driver.FindElement(By.Name("target")); (new Actions(driver)).DragAndDrop(element, target).Perform();
//模擬遊標晃動movebyoffset() Actions action = new Actions(driver); action.MoveByOffset(2, 4);
//WebDriver中自帶截圖功能 Screenshot screenShotFile = ((ITakesScreenshot)driver).GetScreenshot(); screenShotFile.SaveAsFile("test", ImageFormat.Jpeg);
driver.execute_script("window.scrollTo(0,document.body.scrollHeight);")
要在不同的瀏覽器視窗之間切換,必須獲得不同的視窗(標籤)的識別符號。用一個集合來儲存這些資料。當需要到新視窗裡進行操作時,需要將測試器前往新的視窗。開始建立的測試器是對視窗來的,所以當我們需要切換視窗時。需要呼叫 測試器.SwitchTo().window(獲得標識) 這個方法來返回一個新的測試器物件。新的物件是代表的是切換的視窗。程式碼如下:
var service = EdgeDriverService.CreateDefaultService(@".", "msedgedriver.exe"); IWebDriver driver = new OpenQA.Selenium.Edge.EdgeDriver(service); driver.Navigate().GoToUrl("http://tieba.baidu.com/f/search/adv"); //找到註冊元素 IWebElement register = driver.FindElement(By.XPath(@".//*[@id='com_userbar']/ul/li[5]/div/a")); register.Click(); //顯示所有標識 IList<string> listHand = driver.WindowHandles;//拿到所有標識 foreach (string item in listHand) { Console.WriteLine(item); } /*這裡一會插入程式碼*/ Console.ReadKey(); driver.Quit();
效果如下:
下面切換到新開啟的視窗後,輸入一個12345來表示我們成功了
在上面的程式碼基礎下 新增下面程式碼
//切換到註冊視窗再輸入12345 driver.SwitchTo().Window(listHand[1]); driver.FindElement(By.Name("userName")).SendKeys("12345");
結果如圖:
//獲取所有的WindowHandle,關閉所有子視窗 string oldwin = driver.CurrentWindowHandle; ReadOnlyCollection<string> windows = driver.WindowHandles; foreach (var win in windows) { if (win != oldwin) { driver.SwitchTo().Window(win).Close(); } } driver.SwitchTo().Window(oldwin);
1、切換焦點到id為固定值的iframe上
進入頁面後,遊標預設焦點在DefaultContent中,若想要定位到iframe 需要轉換焦點
driver.SwitchTo().DefaultContent(); //切換焦點到mainFrame driver.SwitchTo().Frame("mainFrame");
需要注意的是:切換焦點之後若想切換焦點到其他iframe上 需要先返回到defaultcontent,再切換焦點到指定的iframe上。
2、切換焦點到id值為動態值的iframe上
有時候 頁面上浮出層的id為動態值,此時需要先獲取所有符合記錄的iframe放置在陣列中,然後遍歷陣列切換焦點到目標iframe上。
如下方法:
protected string bizFrameId = string.Empty; protected string bizId = string.Empty; //獲取動態iframe的id值 protected void SetIframeId() { ReadOnlyCollection els = driver.FindElements(By.TagName("iframe")); foreach (var e in driver.FindElements(By.TagName("iframe"))) { string s1 = e.GetAttribute("id"); if (s1.IndexOf("window") >= 0 && s1.IndexOf("content") >= 0) { bizFrameId = e.GetAttribute("id"); string[] ss = s1.Split(new char[] { '_' }); bizId = ss[1]; } } }
在C#中,通過Cookies屬性來獲取當前的Cookie集合,然後進行增刪改查操作。
Cookie由5個部分組成:名稱、值、所在域、路徑和過期時間。
下面我們進入百度首頁,然後獲取cookie,並讓它變動一下來看到效果。 程式碼如下:
var service = EdgeDriverService.CreateDefaultService(@".", "msedgedriver.exe"); IWebDriver driver = new OpenQA.Selenium.Edge.EdgeDriver(service); driver.Navigate().GoToUrl("http://www.baidu.com"); //獲取Cookie ICookieJar listCookie = driver.Manage().Cookies; // IList listCookie = driver.Manage( ).Cookies.AllCookies;//只是顯示 可以用Ilist物件 //顯示初始Cookie的內容 Console.WriteLine("--------------------"); Console.WriteLine($"當前Cookie集合的數量:t{listCookie.AllCookies.Count}"); for (int i = 0; i < listCookie.AllCookies.Count; i++) { Console.WriteLine($"Cookie的名稱:{listCookie.AllCookies[i].Name}"); Console.WriteLine($"Cookie的值:{listCookie.AllCookies[i].Value}"); Console.WriteLine($"Cookie的所在域:{listCookie.AllCookies[i].Domain}"); Console.WriteLine($"Cookie的路徑:{listCookie.AllCookies[i].Path}"); Console.WriteLine($"Cookie的過期時間:{listCookie.AllCookies[i].Expiry}"); Console.WriteLine("-----"); } //新增一個新的Cookie Cookie newCookie = new Cookie("新Cookie", "新值", "", DateTime.Now.AddDays(1)); listCookie.AddCookie(newCookie); Console.WriteLine("--------------------"); Console.WriteLine($"當前Cookie集合的數量:t{listCookie.AllCookies.Count}"); for (int i = 0; i < listCookie.AllCookies.Count; i++) { Console.WriteLine($"Cookie的名稱:{listCookie.AllCookies[i].Name}"); Console.WriteLine($"Cookie的值:{listCookie.AllCookies[i].Value}"); Console.WriteLine($"Cookie的所在域:{listCookie.AllCookies[i].Domain}"); Console.WriteLine($"Cookie的路徑:{listCookie.AllCookies[i].Path}"); Console.WriteLine($"Cookie的過期時間:{listCookie.AllCookies[i].Expiry}"); Console.WriteLine("-----"); } //刪除這個Cookie並再次顯示總數 listCookie.DeleteCookieNamed(newCookie.Name); Console.WriteLine($"當前Cookie集合的數量:t{listCookie.AllCookies.Count}"); Console.ReadLine(); driver.Quit();
執行效果如下:
這個屬性是可以對當前的視窗進行簡單的控制。如獲取座標和大小,還可以將其最大化。下面我們用過範例程式碼來試試效果。
下面的程式碼是先開啟網頁,列印座標和大小,再控制它最大化,再次列印座標和大小。
var service = EdgeDriverService.CreateDefaultService(@".", "msedgedriver.exe"); IWebDriver driver = new OpenQA.Selenium.Edge.EdgeDriver(service); driver.Navigate().GoToUrl("http://www.baidu.com"); //列印現在的座標和大小 IWindow window = driver.Manage().Window; Console.WriteLine("第一次列印"); Console.WriteLine($"座標X為{window.Position.X}tY為{window.Position.Y}"); Console.WriteLine($"大小長為{window.Size.Width}t寬為{window.Size.Height}"); Console.WriteLine("-------------"); //控制最大化 window.Maximize(); //再次列印資料 Console.WriteLine("第二次列印"); Console.WriteLine($"座標X為{window.Position.X}tY為{window.Position.Y}"); Console.WriteLine($"大小長為{window.Size.Width}t寬為{window.Size.Height}"); Console.WriteLine("-------------"); Console.ReadLine(); driver.Quit();
效果如下:
這裡有兩個奇怪的地方:
1.我的螢幕是1080P的,輸出後的資料中,長只有1936.如果減去16的話到正好是1920.但是寬應該是1080,如果工作列的寬度是24的話,到也能說得過去。只是資料和我們要的有點偏差,這裡需要注意一下。
2.window屬性居然只有位置、大小和最大化方法。居然沒有最小化或還原(退出最大化狀態)方法。
首先是準備好要新增的事件,然後再掛接。這裡可以使用C#的語法糖。在+=後面直接按兩次tab鍵,然後再移動到事件區編輯。
eventDriver.Navigating += EventDriver_Navigating;//導航前 eventDriver.Navigated += EventDriver_Navigated;//導航後 eventDriver.FindingElement += EventDriver_FindingElement;//查詢元素前 eventDriver.FindElementCompleted += EventDriver_FindElementCompleted;//查詢元素後 eventDriver.ElementClicking += EventDriver_ElementClicking;//元素單擊前 eventDriver.ElementClicked += EventDriver_ElementClicked;//元素單擊後 eventDriver.ElementValueChanging += EventDriver_ElementValueChanging;//元素值改變前 eventDriver.ElementValueChanged += EventDriver_ElementValueChanged;//元素值改變後 eventDriver.ExceptionThrown += EventDriver_ExceptionThrown;//異常發生後事件
掛接事件:
#region 事件區 /// /// 導航前發生的事件 /// /// /// private void EventDriver_Navigating(object sender, WebDriverNavigationEventArgs e) { this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"即將要跳轉到的URL為:{e.Driver.Url}"); } /// /// 導航後發生的事件 /// /// /// private void EventDriver_Navigated(object sender, WebDriverNavigationEventArgs e) { this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"跳轉到的URL為:{e.Driver.Url}"); } /// /// 查詢元素前發生 /// /// /// private void EventDriver_FindingElement(object sender, FindElementEventArgs e) { this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"即將查詢的元素為:{e.FindMethod.ToString()}"); } /// /// 查詢元素後發生 /// /// /// private void EventDriver_FindElementCompleted(object sender, FindElementEventArgs e) { this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"找到元素,條件為:{e.FindMethod.ToString()}"); } /// /// 單擊元素前發生 /// /// /// private void EventDriver_ElementClicking(object sender, WebElementEventArgs e) { this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"要單擊的元素的value屬性為:{e.Element.GetAttribute("value")}"); } /// /// 單擊元素後發生 /// /// /// private void EventDriver_ElementClicked(object sender, WebElementEventArgs e) { System.Threading.Thread.Sleep(3 * 1000);//暫停3秒 this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"單擊元素後,現在的URL為:{e.Driver.Url}"); } /// /// 單擊元素前發生 /// /// /// private void EventDriver_ElementValueChanging(object sender, WebElementEventArgs e) { this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"元素更改前的值為:{e.Element.GetAttribute("value")}"); } /// /// 單擊元素後發生 /// /// /// private void EventDriver_ElementValueChanged(object sender, WebElementEventArgs e) { this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"元素更改後的值為:{e.Element.GetAttribute("value")}"); } /// /// 異常(儲存截圖到本地) /// /// /// private void EventDriver_ExceptionThrown(object sender, WebDriverExceptionEventArgs e) { //地址 string strPath = $@"D:Desktop{DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss")}.png"; //儲存截圖 Screenshot screen = (sender as EventFiringWebDriver).GetScreenshot(); screen.SaveAsFile(strPath, System.Drawing.Imaging.ImageFormat.Png); //輸出儲存資訊 this.listMeassage.Add("-----------------------------------------"); this.listMeassage.Add($"發生異常,截圖已儲存到:{strPath}"); }
有下面兩種:
下面程式碼的程式碼展示這了兩個方法的用法和用途。
1.開啟百度首頁,單擊“註冊”超級連結。
2.在彈出的視窗(百度賬戶註冊)中,呼叫Close()方法,關閉新彈出的頁面
3.再一次點選“註冊”超級連結,呼叫Quit()方法來結束測試。
var service = EdgeDriverService.CreateDefaultService(@".", "msedgedriver.exe"); IWebDriver driver = new OpenQA.Selenium.Edge.EdgeDriver(service); //導航到百度首頁 driver.Navigate().GoToUrl("http://www.baidu.com"); //進行點選 Console.WriteLine("-------------------"); Console.WriteLine("進行點選"); driver.FindElement(By.LinkText("登入")).Click(); System.Threading.Thread.Sleep(3 * 1000); driver.FindElement(By.LinkText("立即註冊")).Click(); //獲取視窗控制程式碼 IList<string> listHand = driver.WindowHandles; //切換到註冊視窗並關閉 Console.WriteLine("-------------------"); Console.WriteLine("切換到註冊視窗"); driver.SwitchTo().Window(listHand[1]); System.Threading.Thread.Sleep(3 * 1000); Console.WriteLine("-------------------"); Console.WriteLine("關閉註冊視窗"); driver.Close(); System.Threading.Thread.Sleep(3 * 1000); //切換到主視窗並結束測試 Console.WriteLine("-------------------"); Console.WriteLine("切換到主視窗並結束測試"); driver.SwitchTo().Window(listHand[0]); driver.FindElement(By.LinkText("立即註冊")).Click(); System.Threading.Thread.Sleep(3 * 1000); driver.Quit(); Console.ReadLine();
到此這篇關於C#使用selenium實現爬蟲的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45