Beautiful Soup 是一個可以從 HTML 或 XML 文件中提取數據的 Python 庫,它提供了一些簡單的操作方式來幫助你處理文檔導航,查找,修改文檔等繁瑣的工作。因為使用簡單,所以 Beautiful Soup 會幫你節省不少的工作時間。
上一篇文章我們介紹了如何使用 Beautiful Soup 來遍歷文檔中的節點,這片文章我們繼續血學習如何使用 Beautiful Soup 指定文檔中搜索到你想要的內容。
同樣為了故事的順利發展,我們繼續使用之前的 HTML 文本,下文的所有例子都是基于這段文本的。
html_doc = """
<html><head><title>index</title></head>
<body>
<p class="title"><b>首頁</b></p>
<p class="main">我常用的網站
<a href="https://www.google.com" class="website" id="google">Google</a>
<a href="https://www.baidu.com" class="website" id="baidu">Baidu</a>
<a href="https://cn.bing.com" class="website" id="bing">Bing</a>
</p>
<div><!--這是注釋內容--></div>
<p class="content1">...</p>
<p class="content2">...</p>
</body>
"""
soup = BeautifulSoup(html_doc, "lxml")
正式講解搜索文檔之前,我們有必要了解下 Beautiful Soup 的過濾器,這些過濾器在整個搜索的 API 中都有所體現,他們可以被用在 TAG 的 name 中,屬性中,字符串中或他們的混合中。聽起來有點繞是么,看幾個例子就懂了。
1、根據 TAG 的 name 來查找標簽,下面的例子會查找文檔中的所有 b 標簽。同時要注意統一傳入 Unicode 編碼以避免 Beautiful Soup 解析編碼出錯。
# demo 1
tags = soup.find_all('b')
print(tags)
#輸出結果
[<b>首頁</b>]
2、如果傳入正則表達式作為參數,那么 Beautiful Soup 會通過正則表達式的 match() 來匹配內容。
# demo 2
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
#輸出結果
body
b
3、如果傳入列表參數,那么 Beautiful Soup 會將與列表中任一一個元素匹配的內容返回。
# demo 3
for tag in soup.find_all(['a', 'b']):
print(tag)
#輸出結果
<b>首頁</b>
<a class="website" href="https://www.google.com" id="google">Google</a>
<a class="website" href="https://www.baidu.com" id="baidu">Baidu</a>
<a class="website" href="https://cn.bing.com" id="bing">Bing</a>
4、True 可以匹配任何值,下面的例子是查找所有的 TAG 但不會返回字符串。
# demo 4
for tag in soup.find_all(True):
print(tag.name, end=', ')
#輸出結果
html, head, title, body, p, b, p, a, a, a, div, p, p,
5、方法。我們可以定義一個方法,該方法只接受一個參數,若該方法返回 True 則表示當前元素匹配并且被找到,返回 False 意味著沒找到。下面的例子展示了查找所有同時包含 class 屬性和 id 屬性的節點。
# demo 5
def has_id_class(tag):
return tag.has_attr('id') and tag.has_attr('class')
tags = soup.find_all(has_id_class)
for tag in tags:
print(tag)
#輸出結果
<a class="website" href="https://www.google.com" id="google">Google</a>
<a class="website" href="https://www.baidu.com" id="baidu">Baidu</a>
<a class="website" href="https://cn.bing.com" id="bing">Bing</a>
大部分情況字符串過濾器就可以滿足我們的需求,外加這個神奇的方法過濾器,我們就可以實現各種自定義需求了。
該函數搜索當前節點下的所有子節點,其簽名如下find_all( name , attrs , recursive , text , **kwargs )。我們可以傳入指定 TAG 的 name 來查找節點,上面已經舉過例子了,這里不在贅述。我們來看幾個其他的用法。
1、如果我們傳入 find_all() 函數不是搜索內置的參數名,那么搜索是就會將該參數對應到屬性上去。下文的例子表示查找 id 為 google 的節點。
搜索指定名字的屬性時可以使用的參數值包括:字符串,正則表達式,列表,True。也就是我們上文介紹過的過濾器。
# demo 6
tags = soup.find_all(id='google')
print(tags[0]['href'])
for tag in soup.find_all(id=True): # 查找所有包含 id 屬性的 TAG
print(tag['href'])
#輸出結果
https://www.google.com
https://www.google.com
https://www.baidu.com
https://cn.bing.com
2、按照 CSS 類名搜索,但是鏢師 CSS 的關鍵字 class 在 Python 中是內置關鍵字,從 Beautiful Soup 4.1.1 版本開始,可以通過 class_ 參數搜索有指定 CSS 類名的 TAG:
class_ 參數同樣接受不同類型的過濾器:字符串,正則表達式,方法,True。
# demo 7
tags = soup.find_all("a", class_="website")
for tag in tags:
print(tag['href'])
def has_seven_characters(css_class):
return css_class is not None and len(css_class) == 7
for tag in soup.find_all(class_=has_seven_characters):
print(tag['id'])
#輸出結果
https://www.google.com
https://www.baidu.com
https://cn.bing.com
google
baidu
bing
同時,因為 CSS 可以有多個值,所以我們可以分別搜索 CSS 中的每個值。
# demo 8
css_soup = BeautifulSoup('<p class="body strikeout"></p>', 'lxml')
tags = css_soup.find_all("p", class_="strikeout")
print(tags)
#輸出結果
[<p class="body strikeout"></p>]
3、不僅可以按照標簽和 CSS 來搜索整個文檔,還可以使用 text 來按照內容來搜索。同時 text 還可以配合其他屬性一起來完成搜索任務。
# demo 9
tags = soup.find_all(text="Google")
print("google : ", tags)
tags = soup.find_all(text=["Baidu", "Bing"])
print("baidu & bing : ", tags)
tags = soup.find_all('a', text="Google")
print("a[text=google] : ", tags)
#輸出結果
google : ['Google']
baidu & bing : ['Baidu', 'Bing']
a[text=google] : [<a class="website" href="https://www.google.com" id="google">Google</a>]
4、限制返回數量
有時候文檔樹過于龐大,我們不想查查找整棵樹,只想查找指定數量的節點,或者只想查找子節點,而不想查找孫子節點,指定 limit 或者 recursive 參數即可。
# demo 10
tag = soup.find_all("a", limit=1)
print(tag)
tags = soup.find_all("p", recursive=False)
print(tags)
#輸出結果
[<a class="website" href="https://www.google.com" id="google">Google</a>]
[]
因為該對象的兒子節點沒有 p 標簽,所以返回的是空列表。
該函數只會返回一個結果,與 find_all(some_args, limit=1) 是等價的,唯一的區別就是該函數直接返回結果,而 find_all() 函數返回包含一個結果的列表。另外 find_all() 方法沒有找到目標是返回空列表, find() 方法找不到目標時,返回 None。除此之外使用上沒有其他差別。
除了 find_all() 和 find() 外,Beautiful Soup 中還有 10 個用于搜索的 API,其中中五個用的是與 find_all() 相同的搜索參數,另外 5 個與 find() 方法的搜索參數類似,區別僅是它們搜索文檔的范圍不同。
find_parents() 和 find_parent() 用來搜索當前節點的父節點。
find_next_siblings() 和 find_next_sibling() 對在當前節點后面解析的所有兄弟節點進行迭代。
find_previous_siblings() 和 find_previous_sibling() 對在當前節點前面解析的所有兄弟節點進行迭代。
find_all_next() 和 find_next() 對當前節點之后的 TAG 和字符串進行迭代。
find_all_previous() 和 find_previous() 對當前節點之前的 TAG 和字符串進行迭代。
以上五組函數的區別僅僅是前者返回一個所有符合搜索條件的節點列表,而后者只返回第一個符合搜索條件的節點。
因為這 10 個 API 的使用和 find_all() 與 find() 大同小異,所有i這里不在舉例,讀者可以自己探索。
在 Tag 或 BeautifulSoup 對象的 .select() 方法中傳入字符串參數即可使用 CSS 選擇器的語法找到 TAG。
1、通過某個標簽逐層查找。
# demo 11
tags = soup.select("body a")
for tag in tags:
print(tag['href'])
#輸出結果
https://www.google.com
https://www.baidu.com
https://cn.bing.com
2、查找某個標簽下的直接子標簽
# demo 12
tags = soup.select("p > a")
print(tags)
tags = soup.select("p > #google")
print(tags)
#輸出結果
[<a class="website" href="https://www.google.com" id="google">Google</a>, <a class="website" href="https://www.baidu.com" id="baidu">Baidu</a>, <a class="website" href="https://cn.bing.com" id="bing">Bing</a>]
[<a class="website" href="https://www.google.com" id="google">Google</a>]
3、通過 CSS 類名直接查找
# demo 13
tags = soup.select(".website")
for tag in tags:
print(tag.string)
#輸出結果
Google
Baidu
Bing
4、通過標簽的 id 屬性查找
# demo 14
tags = soup.select("#google")
print(tags)
#輸出結果
[<a class="website" href="https://www.google.com" id="google">Google</a>]
5、通過屬性的值來查找
# demo 15
tags = soup.select('a[href="https://cn.bing.com"]')
print(tags)
#輸出結果
[<a class="website" href="https://cn.bing.com" id="bing">Bing</a>]
本章節介紹了 Beautiful Soup 關于文檔搜索的相關操作,熟練掌握這些 API 的操作可以讓我們更快更好找到我們想要定位的節點,不要看到這么多函數嚇怕了,其實我們只需要熟練掌握 find_all() 和 find() 兩個函數即可,其余 API 的使用都大同小異,稍加練習即可快速上手。
編親身體驗,教你如何用Js獲取頁面關鍵詞
在網絡時代,關鍵詞的重要性不言而喻。無論是SEO優化,還是網站內容策劃,都需要準確獲取頁面關鍵詞。但是,如何用Js獲取頁面關鍵詞呢?小編今天就來為大家分享一下親身體驗的方法。
一、了解Js獲取頁面關鍵詞的原理
在深入了解如何用Js獲取頁面關鍵詞之前,我們先來了解一下其原理。通常情況下,搜索引擎會根據網頁的標題、描述和內容等信息來確定關鍵詞。而Js獲取頁面關鍵詞的方法就是通過解析網頁源代碼,提取其中的文本內容,并進行分析和處理,最終得到頁面的關鍵詞。
二、使用正則表達式提取關鍵詞
使用正則表達式是一種常見且有效的方法來提取頁面的關鍵詞。我們可以通過正則表達式匹配特定的字符或者字符組合,并將其作為關鍵詞進行保存和處理。
具體操作步驟如下:
1.獲取網頁源代碼
使用`document.documentElement.outerHTML`可以獲取當前網頁的源代碼。
2.匹配關鍵詞
使用正則表達式`/\/`可以匹配到網頁中的關鍵詞。
3.提取關鍵詞
使用`match()`方法可以將匹配到的關鍵詞提取出來,并保存在一個數組中。
4.處理關鍵詞
可以使用循環遍歷的方式對提取到的關鍵詞進行處理,比如去除空格、轉換為小寫等。
5.顯示關鍵詞
最后,可以將處理后的關鍵詞顯示在頁面上,供用戶參考和使用。
三、Js獲取頁面關鍵詞的注意事項
在實際應用中,我們還需要注意以下幾點:
1.關鍵詞的數量和質量都很重要,不宜過多也不宜過少。一般來說,3~5個關鍵詞比較合適。
2.關鍵詞應該與網頁內容密切相關,避免出現無關或重復的關鍵詞。
3.頁面的標題、描述和內容也是搜索引擎確定關鍵詞的重要依據,因此需要合理設置和優化。
4. Js獲取頁面關鍵詞只是一種輔助手段,不能代替其他SEO優化措施和策略。
五、總結
通過上述步驟,我們可以輕松地使用Js獲取頁面關鍵詞。當然,在實際應用中還有很多細節需要注意,這需要我們根據具體情況進行調整和優化。希望本文對大家有所幫助,謝謝閱讀!
六、參考代碼
javascript //獲取網頁源代碼 var html = document.documentElement.outerHTML; //匹配關鍵詞 var regex =/\<meta\sname=\"keywords\"\scontent=\"(.*?)\"\>/; var matches = html.match(regex); //提取關鍵詞 var keywords =[]; if (matches && matches.length >1){ keywords = matches[1].split(","); } //處理關鍵詞 for (var i =0; i < keywords.length;i++){ keywords[i]= keywords[i].trim().toLowerCase(); } //顯示關鍵詞 console.log(keywords);
以上就是小編親身體驗的Js獲取頁面關鍵詞的方法,希望能對大家有所啟發和幫助。如果還有其他問題,請隨時留言,小編會盡快回復解答。謝謝!
近有個需求,在一個react項目中,實現搜索關鍵字呈現高亮狀態。這個在普通的html文件中還好操作些,在react項目中有點懵逼了,因為react項目中很少操作dom,有點無從下手。但最后還是實現了效果,如下:
首先來看看如何在react中操作dom,廣大網友給出兩種方案:
一:使用選擇器:
1、引入react-dom
import ReactDom from 'react-dom'
2、給react節點設置id或類名等標識
<span id='tip'></span>
3、定義變量保存dom元素
var span = document.getElementById('tip')
4、通過ReactDom的findDOMNode()方法修改dom的屬性
ReactDom.findDOMNode(span).style.color = 'red'
二:使用ref屬性
1、給指定標簽設置ref屬性
<span ref='tip'></span>
2、通過this.refs.ref屬性值來修改標簽的屬性
this.refs.tip.style.color = "red"
我用第二種方案來操作的:
import React from 'react';
import { Input } from 'antd';
const { Search } = Input;
// 高亮測試
class Highlight extends React.Component {
constructor(props) {
super(props);
this.state = {
text:<p>writing to a TLS enabled socket, node::StreamBase::Write calls node::TLSWrap::DoWrite with a freshly allocated WriteWrap object as first argument. If the DoWrite method does not return an error, this object is passed back to the caller as part of a StreamWriteResult structure. This may be exploited to corrupt memory leading to a Denial of Service or potentially other exploits\n" +
HTTP Request Smuggling in nodejs Affected versions of Node.js allow two copies of a header field in a http request. For example, two Transfer-Encoding header fields. In this case Node.js identifies the first header field and ignores the second. This can lead to HTTP Request Smuggling (https://cwe.mitre.org/data/definitions/444.html).\n" +
OpenSSL - EDIPARTYNAME NULL pointer de-reference (High) This is a vulnerability in OpenSSL which may be exploited through Node.js. You can read more about it in https://www.openssl.org/news/secadv/20201208.txt</p>
};
}
findHighlight = (keyWord)=>{
const str=keyWord.replace(/^(\s|\xA0)+|(\s|\xA0)+$/g, '');
// eslint-disable-next-line react/no-string-refs
const val= this.refs.tip.innerHTML;
const content = this.searchdo(val, str);
// eslint-disable-next-line react/no-string-refs
this.refs.tip.innerHTML=content;
};
searchdo=(content,keyWord)=>{
const keyWordArr = keyWord.split(' ');
let re;
for(let n = 0; n < keyWordArr.length; n +=1) {
re = new RegExp(`${keyWordArr[n]}`,"gmi");
// eslint-disable-next-line no-param-reassign
content = content.replace(re,`<span style="color:#0f0;background-color:#ff0">${keyWordArr[n]}</span>`);
}
return content;
};
render() {
const { text} = this.state;
return (
<div>
<Search
placeholder="請輸入查找內容"
onSearch={value => this.findHighlight(value)}
style={{ width: 200 }}
/>
<br />
<br />
<div
style={{
border:"1px solid #ccc",
borderRadius:"4px",
padding:"5px"
}}
ref="tip"
>
{text}
</div>
</div>
);
}
}
export default Highlight;
然后就實現了上面的效果,但是這只是最初步的,如果需要完善功能還需要自己進一步改造。
這只是其中一種方案,我還會用另一種方案實現這個效果(更加詳解和優化),對你有用的話,歡迎關注!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。