Html 민첩성 팩은 클래스별로 모든 요소를 ​​가져옵니다.

c# html html-agility-pack

문제

나는 html 민첩성 팩에 찔러 들고 이것에 대해 올바른 방법을 찾는데 어려움을 겪고있다.

예 :

var findclasses = _doc.DocumentNode.Descendants("div").Where(d => d.Attributes.Contains("class"));

그러나 분명히 당신은 클래스를 더 많은 div에 추가 할 수 있습니다. 그래서 div를 시도했습니다.

var findclasses = _doc.DocumentNode.Descendants("div").Where(d => d.Attributes.Contains("class"));

하지만 그것은 여러 클래스를 추가하는 경우를 처리하지 않으며 "float"은이 중 하나 일뿐입니다.

var findclasses = _doc.DocumentNode.Descendants("div").Where(d => d.Attributes.Contains("class"));

이 모든 것을 처리 할 수있는 방법이 있습니까? 기본적으로 클래스가있는 모든 노드를 선택하고 float가 포함됩니다.

** 답변은 내 블로그에 전체 설명과 함께 문서화되어 있습니다 : Html 민첩성 팩 클래스로 모든 요소를 ​​가져 오기

수락 된 답변

(2018-03-17 업데이트)

문제 :

문제는 String.Contains 가 단어 경계 검사를 수행하지 않는다는 것입니다. 따라서 Contains("float") 는 "foo float bar"(올바른)와 "unfloating"(둘 다)에 대해 true 를 반환 true 부정확 함).

해결책은 양측 의 단어 경계 옆에 "float"(또는 원하는 클래스 이름이 무엇이든)이 나타나는지 확인 하는 것 입니다. 단어 경계는 문자열 (또는 줄)의 시작 (또는 끝), 공백, 특정 구두법 등입니다. 대부분의 정규 표현식에서 이것은 \b 입니다. 그래서 당신이 원하는 정규식은 간단합니다 : \bfloat\b .

Regex 인스턴스를 사용할 때의 단점은 .Compiled 옵션을 사용하지 않으면 실행 속도가 느려질 수 있으며 컴파일 속도가 느려질 수 있다는 것입니다. 그래서 당신은 regex 인스턴스를 캐시해야합니다. 런타임에 변경하려는 클래스 이름이 있으면이 작업이 더 어려워집니다.

또는 정규 표현식을 사용하지 않고 C # 문자열 처리 함수로 정규식을 사용하지 않고 단어 경계로 단어를 검색 할 수 있습니다. 새 문자열이나 다른 객체 할당 (예 : String.Split 사용하지 않음)이 발생하지 않도록주의하십시오.

접근법 1 : 정규식 사용 :

디자인 타임에 지정된 단일 class-name을 가진 요소를 찾고자한다고 가정 해보십시오.

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", "") ) );
    }
}

런타임에 단일 클래스 이름을 선택해야하는 경우 정규식을 만들 수 있습니다.

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", "") ) );
    }
}

여러 클래스 이름을 가지고 있고 그들 모두 일치 할 경우의 배열을 만들 수 Regex 객체를 그들이 일치하는 모든 것, 또는 단일로 결합 보장 Regex lookarounds를 사용하지만,이 결과 엄청나게 복잡한 표현식에서 - 그래서 Regex[] 사용하는 것이 더 좋다 :

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", "") ) );
    }
}

접근법 2 : 정규식이 아닌 문자열 일치 사용 :

정규식 대신 문자열 일치를 수행하는 데 사용자 지정 C # 메서드를 사용하면 성능이 향상되고 메모리 사용량이 줄어 듭니다 ( Regex 는 일부 상황에서는 더 빠를 수 있지만 항상 코드에서 먼저 코드를 작성합니다!).

이 메소드는 다음과 같습니다 : CheapClassListContainsCheapClassListContains 와 같은 방식으로 사용할 수있는 빠른 단어 경계 검사 문자열 일치 기능을 regex.IsMatch .

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", "") ) );
    }
}

접근법 3 : CSS 선택기 라이브러리 사용 :

HtmlAgilityPack은 다소 정체되어 있습니다 .querySelector.querySelectorAll 지원하지 않지만 .querySelector 을 확장하는 타사 라이브러리, 즉 FizzlerCssSelectors가 있습니다. 두 Fizzler 및 CssSelectors 구현 QuerySelectorAll 당신과 같이 사용할 수 있습니다 :

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", "") ) );
    }
}

런타임 정의 클래스 사용 :

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", "") ) );
    }
}

인기 답변

아래와 같이 Xpath 쿼리에서 'contains'함수를 사용하여 문제를 해결할 수 있습니다.

var allElementsWithClassFloat = 
   _doc.DocumentNode.SelectNodes("//*[contains(@class,'float')]")

함수에서이를 재사용하려면 다음과 유사한 작업을 수행하십시오.

var allElementsWithClassFloat = 
   _doc.DocumentNode.SelectNodes("//*[contains(@class,'float')]")



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.