Html Agility Pack은 클래스별로 모든 요소를 가져옵니다.
나는 html 민첩성 팩을 찌르고 있으며 올바른 방법을 찾는 데 어려움을 겪고 있습니다.
예를 들면 :
var findclasses = _doc.DocumentNode.Descendants("div").Where(d => d.Attributes.Contains("class"));
그러나 분명히 div보다 더 많은 클래스를 추가 할 수 있으므로 이것을 시도했습니다 ..
var allLinksWithDivAndClass = _doc.DocumentNode.SelectNodes("//*[@class=\"float\"]");
그러나 그것은 여러 클래스를 추가하는 경우를 처리하지 못하며 "float"는 이러한 클래스 중 하나 일뿐입니다 ..
class="className float anotherclassName"
이 모든 것을 처리 할 수있는 방법이 있습니까? 기본적으로 클래스가 있고 float를 포함하는 모든 노드를 선택하고 싶습니다.
** 답변은 내 블로그에 전체 설명과 함께 문서화되어 있습니다. Html Agility Pack Get All Elements by Class
(2018 년 3 월 17 일 업데이트 됨)
문제 :
문제 String.Contains
는 단어 경계 검사를 수행하지 않으므로 "foo float bar"(올바른) 및 "unfloating"(잘못된) 모두에 대해 Contains("float")
반환된다는 것 true
입니다.
해결책은 "float"(또는 원하는 클래스 이름이 무엇이든)가 양쪽 끝에 단어 경계와 함께 표시되도록 하는 것 입니다. 단어 경계는 문자열 (또는 줄)의 시작 (또는 끝), 공백, 특정 구두점 등입니다. 대부분의 정규 표현식에서 이것은입니다 \b
. 따라서 원하는 정규식은 간단 \bfloat\b
합니다..
Regex
인스턴스 사용의 단점 은 .Compiled
옵션을 사용하지 않으면 실행 속도가 느리고 컴파일 속도가 느릴 수 있다는 것입니다. 따라서 정규식 인스턴스를 캐시해야합니다. 찾고있는 클래스 이름이 런타임에 변경되면 더 어렵습니다.
또는 정규식을 C # 문자열 처리 함수로 구현하여 정규식을 사용하지 않고 단어 경계별로 문자열을 검색 할 수 있습니다. 새 문자열이나 기타 개체 할당이 발생하지 않도록주의합니다 (예 :를 사용하지 않음 String.Split
).
접근 방식 1 : 정규식 사용 :
디자인 타임에 지정된 단일 클래스 이름을 가진 요소를 찾고 싶다고 가정합니다.
class Program {
private static readonly Regex _classNameRegex = new Regex( @"\bfloat\b", RegexOptions.Compiled );
private static IEnumerable<HtmlNode> GetFloatElements(HtmlDocument doc) {
return doc
.Descendants()
.Where( n => n.NodeType == NodeType.Element )
.Where( e => e.Name == "div" && _classNameRegex.IsMatch( e.GetAttributeValue("class", "") ) );
}
}
런타임에 단일 클래스 이름을 선택해야하는 경우 정규식을 빌드 할 수 있습니다.
private static IEnumerable<HtmlNode> GetElementsWithClass(HtmlDocument doc, String className) {
Regex regex = new Regex( "\\b" + Regex.Escape( className ) + "\\b", RegexOptions.Compiled );
return doc
.Descendants()
.Where( n => n.NodeType == NodeType.Element )
.Where( e => e.Name == "div" && regex.IsMatch( e.GetAttributeValue("class", "") ) );
}
여러 클래스 이름을 가지고 있고 그들 모두 일치 할 경우의 배열을 만들 수있는 Regex
객체를 그들이 일치하는 모든 것 확인 또는 단일로 결합 Regex
lookarounds를 사용하지만,이 결과 엄청나게 복잡한 표현식에서이 - 그래서 사용 a Regex[]
가 더 좋습니다.
using System.Linq;
private static IEnumerable<HtmlNode> GetElementsWithClass(HtmlDocument doc, String[] classNames) {
Regex[] exprs = new Regex[ classNames.Length ];
for( Int32 i = 0; i < exprs.Length; i++ ) {
exprs[i] = new Regex( "\\b" + Regex.Escape( classNames[i] ) + "\\b", RegexOptions.Compiled );
}
return doc
.Descendants()
.Where( n => n.NodeType == NodeType.Element )
.Where( e =>
e.Name == "div" &&
exprs.All( r =>
r.IsMatch( e.GetAttributeValue("class", "") )
)
);
}
접근 방식 2 : 정규식이 아닌 문자열 일치 사용 :
사용자 지정 C # 메서드를 사용하여 정규식 대신 문자열 일치를 수행 할 때의 이점은 가상적으로 성능이 더 빠르고 메모리 사용량이 줄어든다 Regex
는 것입니다 (일부 상황에서는 더 빠를 수 있습니다. 항상 코드를 먼저 프로파일 링하십시오!)
이 방법은 다음과 같습니다. CheapClassListContains
다음과 같은 방식으로 사용할 수있는 빠른 단어 경계 검사 문자열 일치 기능을 제공합니다 regex.IsMatch
.
private static IEnumerable<HtmlNode> GetElementsWithClass(HtmlDocument doc, String className) {
return doc
.Descendants()
.Where( n => n.NodeType == NodeType.Element )
.Where( e =>
e.Name == "div" &&
CheapClassListContains(
e.GetAttributeValue("class", ""),
className,
StringComparison.Ordinal
)
);
}
/// <summary>Performs optionally-whitespace-padded string search without new string allocations.</summary>
/// <remarks>A regex might also work, but constructing a new regex every time this method is called would be expensive.</remarks>
private static Boolean CheapClassListContains(String haystack, String needle, StringComparison comparison)
{
if( String.Equals( haystack, needle, comparison ) ) return true;
Int32 idx = 0;
while( idx + needle.Length <= haystack.Length )
{
idx = haystack.IndexOf( needle, idx, comparison );
if( idx == -1 ) return false;
Int32 end = idx + needle.Length;
// Needle must be enclosed in whitespace or be at the start/end of string
Boolean validStart = idx == 0 || Char.IsWhiteSpace( haystack[idx - 1] );
Boolean validEnd = end == haystack.Length || Char.IsWhiteSpace( haystack[end] );
if( validStart && validEnd ) return true;
idx++;
}
return false;
}
접근 방식 3 : CSS 선택기 라이브러리 사용 :
HtmlAgilityPack is somewhat stagnated doesn't support .querySelector
and .querySelectorAll
, but there are third-party libraries that extend HtmlAgilityPack with it: namely Fizzler and CssSelectors. Both Fizzler and CssSelectors implement QuerySelectorAll
, so you can use it like so:
private static IEnumerable<HtmlNode> GetDivElementsWithFloatClass(HtmlDocument doc) {
return doc.QuerySelectorAll( "div.float" );
}
With runtime-defined classes:
private static IEnumerable<HtmlNode> GetDivElementsWithClasses(HtmlDocument doc, IEnumerable<String> classNames) {
String selector = "div." + String.Join( ".", classNames );
return doc.QuerySelectorAll( selector );
}
You can solve your issue by using the 'contains' function within your Xpath query, as below:
var allElementsWithClassFloat =
_doc.DocumentNode.SelectNodes("//*[contains(@class,'float')]")
To reuse this in a function do something similar to the following:
string classToFind = "float";
var allElementsWithClassFloat =
_doc.DocumentNode.SelectNodes(string.Format("//*[contains(@class,'{0}')]", classToFind));
I used this extension method a lot in my project. Hope it will help one of you guys.
public static bool HasClass(this HtmlNode node, params string[] classValueArray)
{
var classValue = node.GetAttributeValue("class", "");
var classValues = classValue.Split(' ');
return classValueArray.All(c => classValues.Contains(c));
}
public static List<HtmlNode> GetTagsWithClass(string html,List<string> @class)
{
// LoadHtml(html);
var result = htmlDocument.DocumentNode.Descendants()
.Where(x =>x.Attributes.Contains("class") && @class.Contains(x.Attributes["class"].Value)).ToList();
return result;
}
You can use the following script:
var findclasses = _doc.DocumentNode.Descendants("div").Where(d =>
d.Attributes.Contains("class") && d.Attributes["class"].Value.Contains("float")
);
참고URL : https://stackoverflow.com/questions/13771083/html-agility-pack-get-all-elements-by-class
'Nice programing' 카테고리의 다른 글
산란 용 matplotlib 컬러 바 (0) | 2020.10.28 |
---|---|
편집 텍스트 커서 색상 변경 (0) | 2020.10.28 |
TypeError 가져 오기 : __init __ () 필수 위치 인수 1 개 누락 : 항목이있는 자식 테이블 뒤에 부모 테이블을 추가하려고 할 때 'on_delete' (0) | 2020.10.28 |
네비게이션 컨트롤러의 투명한 모달 뷰 (0) | 2020.10.28 |
루트에서 하위 디렉터리로 IIS7 URL 리디렉션 (0) | 2020.10.28 |