Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 色女人综合网,日本高清视频色,亚洲高清资源

          整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          在 ASP.NET CORE 中使用 SESSION

          ession 是保存用戶和 Web 應(yīng)用的會(huì)話狀態(tài)的一種方法,ASP.NET Core 提供了一個(gè)用于管理會(huì)話狀態(tài)的中間件。在本文中我將會(huì)簡單介紹一下 ASP.NET Core 中的 Session 的使用方法。

          安裝配置 Session

          nuget 添加引用 Microsoft.AspNetCore.Session

          ession 是基于 IDistributedCache 構(gòu)建的,所以必須引用一種 IDistributedCache 的實(shí)現(xiàn),ASP.NET Core 提供了多種 IDistributedCache 的實(shí)現(xiàn) (Redis、SQL Server、In-memory)

          In-memory

          services.AddDistributedMemoryCache();
          services.AddSession();

          SQL Server

          nuget 添加引用 Microsoft.Extensions.Caching.SqlServer

          SqlServerCache實(shí)現(xiàn)允許分布式緩存使用SQL Server數(shù)據(jù)庫作為其后備存儲(chǔ)。要?jiǎng)?chuàng)建SQL Server表,您可以使用sql-cache工具,該工具將使用您指定的名稱和模式創(chuàng)建一個(gè)表。

          要使用sql-cache工具,請?zhí)砑?/span>SqlConfig.Tools.csproj文件的<ItemGroup>元素并運(yùn)行dotnet恢復(fù)。

          <ItemGroup>
            <DotNetCliToolReference Include="Microsoft.Extensions.Caching.SqlConfig.Tools" Version="1.0.0-msbuild3-final" />
          </ItemGroup>

          通過運(yùn)行以下命令來測試SqlConfig.Tools

          C:\DistCacheSample\src\DistCacheSample>dotnet sql-cache create --help

          sql-cache工具將顯示用法,選項(xiàng)和命令幫助,現(xiàn)在你可以創(chuàng)建表到sql server中,運(yùn)行“sql-cache create”命令:

          C:\DistCacheSample\src\DistCacheSample>dotnet sql-cache create "Data Source=(localdb)\v11.0;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache
             info: Microsoft.Extensions.Caching.SqlConfig.Tools.Program[0]
                 Table and index were created successfully.

          創(chuàng)建的表格具有以下架構(gòu):

          注意的ConnectionString(以及可選地,SchemaNameTableName)通常應(yīng)該被存儲(chǔ)的源控制(如UserSecrets)以外,因?yàn)樗鼈兛赡馨瑧{證。

          像所有的緩存實(shí)現(xiàn)一樣,你的應(yīng)用程序應(yīng)該使用一個(gè)實(shí)例來獲取和設(shè)置緩存值IDistributedCache,而不是SqlServerCache。該示例SqlServerCacheProduction環(huán)境中實(shí)現(xiàn)(因此已配置ConfigureProductionServices)。

          // Microsoft SQL Server implementation of IDistributedCache.
          // Note that this would require setting up the session state database.
          services.AddDistributedSqlServerCache(o =>
          {
            o.ConnectionString = "Server=.;Database=ASPNET5SessionState;Trusted_Connection=True;";
            o.SchemaName = "dbo";
            o.TableName = "Sessions";
          });
          services.AddSession();

          Redis

          nuget 添加引用 Microsoft.Extensions.Caching.Redis

          Redis是一款開源的內(nèi)存數(shù)據(jù)存儲(chǔ),通常用作分布式緩存。您可以在本地使用它,并且可以為Azure托管的ASP.NET Core應(yīng)用程序配置Azure Redis緩存。您的ASP.NET Core應(yīng)用程序使用RedisDistributedCache實(shí)例配置緩存實(shí)施。

          您可以ConfigureServices通過請求一個(gè)實(shí)例IDistributedCache(參見上面的代碼)來配置Redis實(shí)現(xiàn)并在您的應(yīng)用代碼中訪問它。

          在示例代碼中,RedisCache當(dāng)為服務(wù)器配置Staging環(huán)境時(shí)使用實(shí)現(xiàn)。因此該ConfigureStagingServices方法配置RedisCache:

          services.AddDistributedRedisCache(options =>  {  options.Configuration = "localhost";  options.InstanceName = "SampleInstance";  });

          接著在 Startup.cs 的 Config 方法中配置使用 Session 中間件,所有中間件的配置順序非常重要,必須在 UseSession 調(diào)用后才能訪問 Session 。

          // 必須在 UseMvc 之前調(diào)用
          app.UseSession();
          
          app.UseMvc(routes =>
          {
              routes.MapRoute(
                  name: "default",
                  template: "{controller=Home}/{action=Index}/{id?}");
          });

          在 AddSession 和 UseSession 方法中可以傳入一個(gè) SessionOptions 參數(shù),通過該參數(shù)可以設(shè)置 Session 的 Cookie name, Cookie path 等信息。

          配置完成后,就可以使用 Session 保存數(shù)據(jù)了。

          具體實(shí)現(xiàn)redis實(shí)現(xiàn) https://www.cnblogs.com/liuxiaoji/p/9259747.html

          使用 Session 存儲(chǔ)數(shù)據(jù)

          Session 安裝配置好就可以通過 HttpContext.Session 來保存和讀取數(shù)據(jù)了。由于 Session 是基于 IDistributedCache 構(gòu)建的,因此 Session 只能存儲(chǔ) byte[] 數(shù)據(jù),這樣使用起來很不方便,好在有很多擴(kuò)展方法可以用來直接讀取和保存 string、int 等類型數(shù)據(jù)。

          一個(gè) Session 使用的簡單示例:

          public IActionResult Index()
          {
              HttpContext.Session.SetString("SessionStartedTime", "Session started time:" + DateTime.Now.ToString());
              return View();
          }
          
          public IActionResult About()
          {
              ViewData["CurrentTime"] = "Current time:" + DateTime.Now.ToString();
              ViewData["SessionStartedTime"] = HttpContext.Session.GetString("SessionStartedTime");
          
              return View();
          }

          或者設(shè)置一個(gè)擴(kuò)展類也可以直接將實(shí)體類序列化成json存儲(chǔ)

          TTP是無狀態(tài)協(xié)議,這意味著每次客戶端檢索網(wǎng)頁時(shí),都要單獨(dú)打開一個(gè)服務(wù)器連接,因此服務(wù)器不會(huì)記錄下先前客戶端請求的任何信息。

          有三種方法來維持客戶端與服務(wù)器的會(huì)話:


          Cookies

          網(wǎng)絡(luò)服務(wù)器可以指定一個(gè)唯一的session ID作為cookie來代表每個(gè)客戶端,用來識(shí)別這個(gè)客戶端接下來的請求。

          這可能不是一種有效的方式,因?yàn)楹芏鄷r(shí)候?yàn)g覽器并不一定支持cookie,所以我們不建議使用這種方法來維持會(huì)話。


          隱藏表單域

          一個(gè)網(wǎng)絡(luò)服務(wù)器可以發(fā)送一個(gè)隱藏的HTML表單域和一個(gè)唯一的session ID,就像下面這樣:

          <input type="hidden" name="sessionid" value="12345">

          這個(gè)條目意味著,當(dāng)表單被提交時(shí),指定的名稱和值將會(huì)自動(dòng)包含在GET或POST數(shù)據(jù)中。每當(dāng)瀏覽器發(fā)送一個(gè)請求,session_id的值就可以用來保存不同瀏覽器的軌跡。

          這種方式可能是一種有效的方式,但點(diǎn)擊<A HREF>標(biāo)簽中的超鏈接時(shí)不會(huì)產(chǎn)生表單提交事件,因此隱藏表單域也不支持通用會(huì)話跟蹤。


          重寫URL

          您可以在每個(gè)URL后面添加一些額外的數(shù)據(jù)來區(qū)分會(huì)話,服務(wù)器能夠根據(jù)這些數(shù)據(jù)來關(guān)聯(lián)session標(biāo)識(shí)符。

          舉例來說,http://w3cschool.cc/file.htm;sessionid=12345, session標(biāo)識(shí)符為sessionid=12345,服務(wù)器可以用這個(gè)數(shù)據(jù)來識(shí)別客戶端。

          相比而言,重寫URL是更好的方式來,就算瀏覽器不支持cookies也能工作,但缺點(diǎn)是您必須為每個(gè)URL動(dòng)態(tài)指定session ID,就算這是個(gè)簡單的HTML頁面。


          session對象

          除了以上幾種方法外,JSP利用servlet提供的HttpSession接口來識(shí)別一個(gè)用戶,存儲(chǔ)這個(gè)用戶的所有訪問信息。

          默認(rèn)情況下,JSP允許會(huì)話跟蹤,一個(gè)新的HttpSession對象將會(huì)自動(dòng)地為新的客戶端實(shí)例化。禁止會(huì)話跟蹤需要顯式地關(guān)掉它,通過將page指令中session屬性值設(shè)為false來實(shí)現(xiàn),就像下面這樣:

          <%@ page session="false" %>

          JSP引擎將隱含的session對象暴露給開發(fā)者。由于提供了session對象,開發(fā)者就可以方便地存儲(chǔ)或檢索數(shù)據(jù)。

          下表列出了session對象的一些重要方法:

          S.N.方法 & 描述
          1public Object getAttribute(String name)返回session對象中與指定名稱綁定的對象,如果不存在則返回null
          2public Enumeration getAttributeNames()返回session對象中所有的對象名稱
          3public long getCreationTime()返回session對象被創(chuàng)建的時(shí)間, 以毫秒為單位,從1970年1月1號(hào)凌晨開始算起
          4public String getId()返回session對象的ID
          5public long getLastAccessedTime()返回客戶端最后訪問的時(shí)間,以毫秒為單位,從1970年1月1號(hào)凌晨開始算起
          6public int getMaxInactiveInterval()返回最大時(shí)間間隔,以秒為單位,servlet 容器將會(huì)在這段時(shí)間內(nèi)保持會(huì)話打開
          7public void invalidate()將session無效化,解綁任何與該session綁定的對象
          8public boolean isNew()返回是否為一個(gè)新的客戶端,或者客戶端是否拒絕加入session
          9public void removeAttribute(String name)移除session中指定名稱的對象
          10public void setAttribute(String name, Object value) 使用指定的名稱和值來產(chǎn)生一個(gè)對象并綁定到session中
          11public void setMaxInactiveInterval(int interval)用來指定時(shí)間,以秒為單位,servlet容器將會(huì)在這段時(shí)間內(nèi)保持會(huì)話有效

          JSP Session應(yīng)用

          這個(gè)例子描述了如何使用HttpSession對象來獲取創(chuàng)建時(shí)間和最后一次訪問時(shí)間。我們將會(huì)為request對象關(guān)聯(lián)一個(gè)新的session對象,如果這個(gè)對象尚未存在的話。

          <%@ page language="java" contentType="text/html; charset=UTF-8"
           pageEncoding="UTF-8"%><%@ page import="java.io.*,java.util.*" %><%
           // 獲取session創(chuàng)建時(shí)間
           Date createTime = new Date(session.getCreationTime());
           // 獲取最后訪問頁面的時(shí)間
           Date lastAccessTime = new Date(session.getLastAccessedTime());
           String title = "再次訪問菜鳥教程實(shí)例";
           Integer visitCount = new Integer(0);
           String visitCountKey = new String("visitCount");
           String userIDKey = new String("userID");
           String userID = new String("ABCD");
           // 檢測網(wǎng)頁是否由新的訪問用戶
           if (session.isNew()){
           title = "訪問菜鳥教程實(shí)例";
           session.setAttribute(userIDKey, userID);
           session.setAttribute(visitCountKey, visitCount);
           } else { visitCount = (Integer)session.getAttribute(visitCountKey); visitCount += 1; userID = (String)session.getAttribute(userIDKey); session.setAttribute(visitCountKey, visitCount);
           }%><html><head><title>Session 跟蹤</title></head><body><h1>Session 跟蹤</h1><table border="1" align="center"> <tr bgcolor="#949494">
           <th>Session 信息</th>
           <th>值</th></tr> <tr>
           <td>id</td>
           <td><% out.print( session.getId()); %></td></tr> <tr>
           <td>創(chuàng)建時(shí)間</td>
           <td><% out.print(createTime); %></td></tr> <tr>
           <td>最后訪問時(shí)間</td>
           <td><% out.print(lastAccessTime); %></td></tr> <tr>
           <td>用戶 ID</td>
           <td><% out.print(userID); %></td></tr> <tr>
           <td>訪問次數(shù)</td>
           <td><% out.print(visitCount); %></td></tr> </table> </body></html>

          試著訪問 http://localhost:8080/testjsp/main.jsp ,第一次運(yùn)行時(shí)將會(huì)得到如下結(jié)果:

          再次訪問,將會(huì)得到如下結(jié)果:


          刪除Session數(shù)據(jù)

          當(dāng)處理完一個(gè)用戶的會(huì)話數(shù)據(jù)后,您可以有如下選擇:

          • 移除一個(gè)特定的屬性:

            調(diào)用public void removeAttribute(String name) 方法來移除指定的屬性。

          • 刪除整個(gè)會(huì)話:

            調(diào)用public void invalidate() 方法來使整個(gè)session無效。

          • 設(shè)置會(huì)話有效期:

            調(diào)用 public void setMaxInactiveInterval(int interval) 方法來設(shè)置session超時(shí)。

          • 登出用戶:

            支持servlet2.4版本的服務(wù)器,可以調(diào)用 logout()方法來登出用戶,并且使所有相關(guān)的session無效。

          • 配置web.xml文件:

            如果使用的是Tomcat,可以向下面這樣配置web.xml文件:

           <session-config>
           <session-timeout>15</session-timeout>
           </session-config>

          超時(shí)以分鐘為單位,Tomcat中的默認(rèn)的超時(shí)時(shí)間是30分鐘。

          Servlet中的getMaxInactiveInterval( ) 方法以秒為單位返回超時(shí)時(shí)間。如果在web.xml中配置的是15分鐘,則getMaxInactiveInterval( ) 方法將會(huì)返回900。

          • 基本使用
            • 發(fā)送請求
            • 解析響應(yīng)獲
          • 獲取需要的內(nèi)容
            • 快速獲取鏈接
            • 獲取元素
          • 高級功能
            • JS渲染
            • 自動(dòng)翻頁(不太好用)
          • 異步
            • 異步渲染JS
            • 異步發(fā)送請求

          初識(shí)requests_html模塊

          感覺只要學(xué)過Python爬蟲的同學(xué)應(yīng)該都知道requests這個(gè)庫吧,它在我們的Python爬蟲任務(wù)中應(yīng)該是最常用的一個(gè)庫了!今天跟大家分享的這個(gè)模塊requests_html,他的作者和前者是同一人!這是一個(gè)解析HTML的庫,用起來和requests一樣方便,下面就來介紹一下它!

          • 參考視頻

          使用requests_html

          安裝

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

          基本使用

          發(fā)送請求

          • requests_html發(fā)送請求獲取頁面需要先實(shí)例化一個(gè)HTMLSession對象,然后使用get/post...方法獲取響應(yīng),如下列代碼
          #!/usr/bin/env python3
          # coding     : utf-8
          # Author     : xiao qiang
          # 微信公眾號(hào)   : 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()  # 獲取實(shí)例化session對象
              r = session.get(url)    # 這里的請求和requests的幾乎一樣!同樣可以根據(jù)需要添加headers等參數(shù)
          
          • requests_html發(fā)送請求的方式和requests中使用session方式發(fā)送請求幾乎是一樣的,可以對比參考
          • requests_html同樣可以發(fā)送get/post等請求,且可以和requests同樣攜帶headers/data等參數(shù),具體用法參考requests

          解析響應(yīng)獲

          • 接上,我們需要將獲取的響應(yīng)解析獲取html頁面,在這里我們同樣可以使用requests中的r.content.decode()等原方法!
          • 但是在requests_html中還提供了更便捷的方法:r.html.html
          • r.html.html實(shí)際上是使用了requests_html中的HTML類(負(fù)責(zé)對HTML進(jìn)行解析)來進(jìn)行解析!如下
          #!/usr/bin/env python3
          # coding     : utf-8
          # Author     : xiao qiang
          # 微信公眾號(hào)   : 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()  # 獲取實(shí)例化session對象
              r = session.get(url)  # 這里的請求和requests的幾乎一樣!同樣可以根據(jù)需要添加headers等參數(shù)
          
              # 獲取html頁面
              # html = r.content.decode()  # requests方式
              get_html = r.html.html  # requests_html中的方法
              print(get_html[:15], '...')
          
          • 運(yùn)行結(jié)果(這里只顯示了部分結(jié)果!)

          獲取需要的內(nèi)容

          快速獲取鏈接

          • requests_html中提供了快速獲取網(wǎng)址鏈接的方法
          • 使用linksabsolute_links兩個(gè)屬性分別可以返回HTML對象所包含的所有鏈接和絕對鏈接(均不包含錨點(diǎn))
          # 快速獲取鏈接
          pprint(r.html.links)  # 獲取html中的鏈接(href屬性)
          pprint(r.html.absolute_links)  # 會(huì)自動(dòng)拼接url生成絕對鏈接
          
          • 部分運(yùn)行結(jié)果如下

          獲取元素

          • requests_html中的HTML對象可以直接使用xpathcss選擇器

          使用xpath

          • requests_html中的HTML對象支持xpath語法,它有以下幾個(gè)參數(shù):
          def xpath(self, selector: str, *, clean: bool = False, first: bool = False, _encoding: str = None) -> _XPath:
          - selector,要用的 xpath選擇器;
          - clean,布爾值,如果為True,會(huì)清除HTML中style和script標(biāo)簽;
          - first,布爾值,如果為True,會(huì)返回第一個(gè)元素,否則會(huì)返回滿足條件的元素列表;
          - _encoding,編碼格式。
          
          • 接上面的例子!使用獲取到的響應(yīng)得到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)
          
          • 運(yùn)行結(jié)果
          • xpath語法

          使用css選擇器(find方法)

          • requests_html中的HTML對象支持css選擇器,它有以下幾個(gè)參數(shù):
          def find(self, selector: str = "*", *, containing: _Containing = None, clean: bool = False, first: bool = False, _encoding: str = None) -> _Find:
          - selector,要用的CSS選擇器;
          - clean,布爾值,如果為True,會(huì)清除HTML中style和script標(biāo)簽;
          - containing,如果設(shè)置該屬性,只返回包含該屬性文本的標(biāo)簽;
          - first,布爾值,如果為True,會(huì)返回第一個(gè)元素,否則會(huì)返回滿足條件的元素列表;
          - _encoding,編碼格式。
          
          • 接上面的例子!使用獲取到的響應(yīng)得到HTML對象r.html
          pprint(r.html.find('a.mnav'))
          pprint(r.html.find('a.mnav', first=True).text)
          
          • 運(yùn)行結(jié)果
          • css選擇器語法
          • 可以使用text屬性來獲取元素的文本內(nèi)容

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

          • 執(zhí)行結(jié)果
          • 如果要獲取元素的attribute,用attrs屬性

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

          • 執(zhí)行結(jié)果
          • 獲取到attrs屬性后,就可以使用字典的相關(guān)方法獲取內(nèi)容了!
          • 最后還可以使用html屬性獲取一個(gè)元素的html代碼,如下

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

          • 執(zhí)行結(jié)果

          正則搜索(search、search_all)

          • requests_html除了上面的方式還可以使用search/search_all來直接搜索內(nèi)容,返回的是一個(gè)Result對象/Result對象列表實(shí)際上是作者將re正則進(jìn)行了封裝)!
          def search(self, template: str) -> Result:
          # 只有一個(gè)參數(shù)
          template: 就是要檢索的內(nèi)容,這里使用英文狀態(tài)的 {} 來獲取內(nèi)容,有點(diǎn)類似正則里面的 ()
          
          • 使用英文狀態(tài)的 {} 來獲取內(nèi)容,如下
              ret = r.html.find('a.mnav')[0].search('新{}')
              pprint(ret)
              pprint(type(ret))
              pprint(ret[0])
          
          • 執(zhí)行結(jié)果
          • search()獲取到的是第一個(gè)匹配的對象,而searchh_all()則是獲取所有匹配的對象,得到的是一個(gè)列表,如下

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

          • 運(yùn)行結(jié)果
          • 除了對某個(gè)元素進(jìn)行檢索外,還可以直接對html對象進(jìn)行搜索,如下

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

          • 運(yùn)行結(jié)果
          • requests_html內(nèi)容提取的方式這么多,大家可以根據(jù)需要和習(xí)慣選擇使用!

          search補(bǔ)充

          • 在上面提到的search()/search_all()方法中,我們設(shè)定的template參數(shù)可以有多個(gè)取值(多個(gè){}),得到的結(jié)果是一個(gè)列表,我們可以遍歷別表進(jìn)行取值 取值的時(shí)候可以通過result[索引]的方式進(jìn)行獲取對應(yīng)的數(shù)據(jù),如下(示例部分代碼) search_ret = r.html.search_all('<a h{}f="{}"',)
            print(search_ret)
            for ret in search_ret:
            print(ret)
            print(ret[1])
            print('--------------')
            運(yùn)行結(jié)果(部分)
          • 除此之外,我們還可以對取值進(jìn)行命名,返回的結(jié)果是可以使用類似字典(不是字典)[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('--------------')
          • 運(yùn)行結(jié)果(部分)
          • 以上就是對requests_html模塊search()/search_all()方法的補(bǔ)充內(nèi)容!

          HTML類

          • requests_html中使用HTML類負(fù)責(zé)對HTML進(jìn)行解析
          • HTML類不僅可以解析網(wǎng)絡(luò)請求獲取的響應(yīng),還可以直接解析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()方法 后面會(huì)講
          
          >>> 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庫的基礎(chǔ)上整合的html解析&數(shù)據(jù)篩選的功能!
          • 下面要為大家介紹的是requests_html模塊中的一些高級功能:自動(dòng)渲染JS&智能分頁

          JS渲染

          • 我們在做爬蟲項(xiàng)目的時(shí)候會(huì)遇到網(wǎng)站的頁面是由js生成的情況!這個(gè)時(shí)候要么就是自己去一步一步地分析請求,要么就是使用selenium等第三方庫來進(jìn)行渲染頁面,為了解決這個(gè)難題,requests_html模塊中引進(jìn)了pyppeteer,使用pyppeteer可以像使用selenium一樣實(shí)現(xiàn)網(wǎng)站的完整加載!而且pyppeteer是一個(gè)異步模塊!效率會(huì)更高!
          • requests_html模塊在HTML對象的基礎(chǔ)上使用render()方法重新加載js頁面
          • 注意:在第一次使用render()的時(shí)候,系統(tǒng)在用戶目錄(默認(rèn)是~/.pyppeteer/)中下載一個(gè)chromium。下載過程只在第一次執(zhí)行,以后就可以直接使用chromium來執(zhí)行任務(wù)了。在沒有科學(xué)上網(wǎng)的環(huán)境下可能下載速度有點(diǎn)慢,請耐心等待...
          • 下面是一個(gè)官方示例
          >>> 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對象的基礎(chǔ)上使用render()方法重新加載js頁面,它有以下幾個(gè)參數(shù):
          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: 加載頁面失敗的次數(shù)
          - script: 頁面上需要執(zhí)行的JS腳本(可選)
          - wait: 加載頁面前等待的時(shí)間(秒),防止超時(shí)(可選)
          - scrolldown: 頁面向下滾動(dòng)的次數(shù)(整數(shù))
          - sleep: 在頁面初次渲染之后的等待時(shí)間
          - reload: 如果為False,那么頁面不會(huì)從瀏覽器中加載,而是從內(nèi)存中加載,只有設(shè)置為True才會(huì)在瀏覽器中渲染JS
          - keep_page: 如果為True,允許您使用 r.html.page 訪問瀏覽器頁面
          
          • requests_html還支持異步渲染JS[^1]

          自動(dòng)翻頁(不太好用)

          • 很多網(wǎng)站會(huì)出現(xiàn)翻頁的情況,requests_html模塊的HTML對象中提供了一個(gè)next()方法來實(shí)現(xiàn)自動(dòng)翻頁!
          • requests_html模塊在HTML對象的基礎(chǔ)上使用next()方法來實(shí)現(xiàn)自動(dòng)翻頁!它有以下幾個(gè)參數(shù):
          def next(self, fetch: bool = False, next_symbol: _NextSymbol = DEFAULT_NEXT_SYMBOL) -> _Next:
          fetch: 一個(gè)布爾型參數(shù),默認(rèn)為False:直接返回下一頁的 url地址;
                 如果設(shè)置為True:則直接返回下一頁的 HTML對象
          
          • 這個(gè)方法我自己測試了一下,只有一些特定的網(wǎng)站才能實(shí)現(xiàn)這個(gè)功能,requests_html在的源碼中可以看到,作者通過搜索包含'next', 'more', 'older'字段的a標(biāo)簽(因?yàn)橐话闱闆r下我們的下一頁url就是在a標(biāo)簽下的href屬性中),所以只有滿足了他的條件才會(huì)實(shí)現(xiàn)這個(gè)功能(也就是說HTML頁面不按照這個(gè)套路它就無法實(shí)現(xiàn)這個(gè)功能!),下面是部分源碼
          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標(biāo)簽
          
          • 這里我就不做舉例了,大家可以自行去嘗試!

          異步

          • requests_html中還支持了異步功能
          • requests_html是使用了asynico來封裝了一些異步操作,所以這里的一些操作會(huì)用到asynico庫相關(guān)的一些知識(shí),如果您還不太了解,請自行學(xué)習(xí)!

          異步渲染JS

          • 前面我們介紹了使用render()方法渲染JS,其實(shí)它還支持異步渲染
          • 一般異步渲染使用在我們有多個(gè)頁面需要進(jìn)行渲染的情況下,因?yàn)橹灰诙嗳蝿?wù)的時(shí)候才能體現(xiàn)出異步的高效率,它有以下幾個(gè)參數(shù):
          def __init__(self, loop=None, workers=None, mock_browser: bool = True, *args, **kwargs):
          loop: 使用的Asyncio循環(huán)。
          workers: 用于執(zhí)行異步調(diào)用的線程數(shù)量。如果不傳遞,它將默認(rèn)為電腦處理器數(shù)量乘以5
          
          • 更多的異步使用方法請參考asyncio庫的使用方法,下面是一個(gè)官方示例
          >>> 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) # 這里作者將同一個(gè)頁面使用異步方式進(jìn)行了3次渲染,但是實(shí)際上使用的時(shí)間并不是平時(shí)的3倍!可能只是比平時(shí)渲染一個(gè)頁面多花了一點(diǎn)時(shí)間而已!這就是異步的好處!
          
          • 注意:results是一個(gè)列表

          異步傳參

          • 這里是后面加的內(nèi)容,因?yàn)槲彝蝗幌氲接袝r(shí)候我們的函數(shù)有可能是帶參數(shù)的,那么這個(gè)時(shí)候我們可以使用lambda來進(jìn)行傳參,看下面示例
          #!/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都是列表
          • 運(yùn)行結(jié)果
          • 上面的示例還可以這樣寫

          #!/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傳參誤區(qū)參考文章:https://www.jianshu.com/p/58ebd1618556
          ret = aSession.run(*tasks)
          # 注意前面有個(gè) *,不可少!# 參考文章:https://www.jianshu.com/p/58ebd1618556
          print(ret)

          • 這里在使用lambda傳參的時(shí)候可能會(huì)出現(xiàn)一個(gè)錯(cuò)誤,可以參考文章解決!
          • 運(yùn)行結(jié)果

          異步發(fā)送請求

          • 我們在做爬蟲的時(shí)候,特別是大型爬蟲的時(shí)候,需要對很多頁面進(jìn)行操作,或者說是需要發(fā)送很多請求,也就是需要進(jìn)行很多IO操作。所以,使用異步發(fā)送請求能顯著地提升我們的爬蟲效率!
          • requests_html模塊中,設(shè)置了一個(gè)AsyncHTMLSession類來實(shí)現(xiàn)發(fā)送異步請求
          • ,下面是一個(gè)官方示例
          >>> 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庫中一些相關(guān)的知識(shí),如果您還不太了解,請自行學(xué)習(xí)!

          總結(jié)

          • requests_html模塊requests庫的基礎(chǔ)上封裝了頁面解析數(shù)據(jù)清理的功能,并且添加了對當(dāng)前比較流行的異步操作,讓我們在做爬蟲項(xiàng)目(一般項(xiàng)目)的時(shí)候無需再去使用多個(gè)第三方模塊來實(shí)現(xiàn)功能,幾乎是提供了一站式的服務(wù)!
          • 所以Python寫爬蟲使用requests_html就對了!(當(dāng)然大項(xiàng)目還是首選scrapy,個(gè)人愚見!)
          • 更多內(nèi)容

          視頻講解源碼

          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()  # 實(shí)例化session
                  self.aSession = AsyncHTMLSession()  # 實(shí)例化異步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):
                  """獲取響應(yīng),并返回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標(biāo)簽中的href屬性
                  urls = html.links
                  # pprint(urls)
          
                  # HTML的 absolute_links屬性 可以快速獲取到頁面中 a標(biāo)簽中的href屬性,并返回絕對url地址
          
                  absolute_urls = html.absolute_links
                  pprint(absolute_urls)
          
              # 清洗數(shù)據(jù)(提取數(shù)據(jù))
              def get_data_by_xpath(self):
                  """使用xpath獲取數(shù)據(jù)"""
                  html = self.get_response(self.start_url)
                  a_list = html.xpath('//table//div/a')
                  # pprint(a_list)
          
                  # 提取它的標(biāo)題和url
                  movies_info = dict()
                  for a in a_list:
                      title = a.text  # 獲取標(biāo)題(文本)
                      # print(title)
                      movie_url = a.attrs.get('href')  # 使用 attrs 來解析element元素,并獲得一個(gè)字典
                      # print(movie_url)
                      # print('-----')
                      movies_info[title] = movie_url
          
                  pprint(movies_info)
          
              # 清洗數(shù)據(jù)(提取數(shù)據(jù))
              def get_data_by_css(self):
                  """使用css獲取數(shù)據(jù)"""
                  html = self.get_response(self.start_url)
                  a_list = html.find('tr[class="item"] div a')  # 參考 css選擇器 語法
                  # pprint(a_list)
          
                  # 提取它的標(biāo)題和url
                  movies_info = dict()
                  for a in a_list:
                      title = a.text  # 獲取標(biāo)題(文本)
                      # print(title)
                      movie_url = a.attrs.get('href')  # 使用 attrs 來解析element元素,并獲得一個(gè)字典
                      # print(movie_url)
                      # print('-----')
                      movies_info[title] = movie_url
          
                  pprint(movies_info)
          
              # 清洗數(shù)據(jù)(提取數(shù)據(jù))
              def get_data_by_re(self):
                  """使用css獲取數(shù)據(jù)"""
                  html = self.get_response(self.start_url)
          
                  # search() 獲取第一條匹配的數(shù)據(jù)
                  # first_url = html.search('a href="{}"')  # 參數(shù)可以參考正則,獲取第一條匹配的數(shù)據(jù)
                  # pprint(first_url)
          
                  # search_all() 獲取所有滿足條件的數(shù)據(jù)列表
                  # url_list = html.search_all('a h{}f="{}"')
                  url_list = html.search_all('a h{title}f="{url}"')  # 對取值方式進(jìn)行命名,返回一個(gè)列表
          
                  # pprint(url_list)
                  #
                  # 提取數(shù)據(jù)
                  for url in url_list:
                      print(url)
                      print(url['title'])  # 使用 result[name] 進(jìn)行取值
                      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="活死人軍團(tuán)">'
                  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)
          
                  # 使用一個(gè) render()方法 來加載js(實(shí)際上使用這個(gè)pyppeteer)
                  # html.render(wait=3)  # js加載
                  print(html.html)
          
              async def send_requests_ues_async(self, url):
                  """發(fā)送異步請求"""
          
                  """獲取響應(yīng),并返回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)  # 返回的是一個(gè)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)  # 返回的是一個(gè)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" 發(fā)布,2021年6月17日】


          主站蜘蛛池模板: 制服丝袜一区在线| 久久免费区一区二区三波多野| 日本一区中文字幕日本一二三区视频| 色欲AV无码一区二区三区| 国产一区二区三区乱码| 一区二区高清在线观看| 亚洲日韩AV无码一区二区三区人 | 无码福利一区二区三区| 99精品久久精品一区二区| 精品一区二区三区在线视频观看 | 精品一区精品二区| 日韩欧美一区二区三区免费观看| 无码人妻品一区二区三区精99 | 国产成人精品一区二区A片带套 | 无码日韩人妻AV一区二区三区| 中文字幕乱码人妻一区二区三区| 日韩人妻一区二区三区蜜桃视频 | 国产一区二区三区在线免费 | 国产一区二区三区内射高清| 日本免费一区尤物| 美女视频免费看一区二区 | 亚洲熟妇av一区二区三区漫画| 国产精品一区二区三区99| 久久se精品一区二区影院| 国产福利电影一区二区三区,亚洲国模精品一区 | 国模极品一区二区三区| 亚洲综合色一区二区三区| 久久精品无码一区二区三区不卡| 日韩一区二区三区射精| 国产精品一区电影| 国产精品亚洲产品一区二区三区| 久久久久人妻精品一区三寸蜜桃| 国产伦精品一区二区三区视频猫咪| 国产激情一区二区三区成人91| 中文字幕精品一区二区三区视频| 国产在线精品一区二区三区不卡| 好看的电影网站亚洲一区| 国产福利微拍精品一区二区| 日本精品啪啪一区二区三区| 久久99国产一区二区三区| 亚洲AV成人一区二区三区AV|