HTML 민첩성 팩 - 테이블에서 div를 읽는 InnerText

c# html-agility-pack web-scraping

문제

내 문제는 테이블에서 div InnerText를 가져올 수 없다는 것입니다. 나는 성공적으로 다른 종류의 데이터를 추가했다. 그러나 나는 테이블에서 div를 읽는 법을 모른다.

다음 그림에서는 div를 강조 표시하고 InnerText (이 경우에는 3 번)를 가져와야합니다.

첫 번째 사진을 보려면 여기를 클릭하십시오.

다음 경로를 사용하여이 작업을 수행하려고합니다.

"//div[@class='kal']//table//tr[2]/td[1]/div[@class='cipars']"

하지만 나는 다음과 같은 오류가 나타납니다 :

오류 메시지 그림을 보려면 여기를 클릭하십시오.

코드의 나머지 부분이 올바르게 작성되었다고 가정하면 누구나 올바른 방향으로 나를 가리킬 수 있습니까? 나는 이것을 알아 내기 위해 노력해 왔지만 어떤 결과도 얻을 수 없다.

수락 된 답변

따라서 문제는 XPath 내의 직위에 의존하고 있다는 것입니다. 어떤 경우에는 OK가 될 수 있지만, 여기에는 없는데, 왜냐하면 주어진 tr 에서 첫 번째 td 가 클래스와 함께 div 를 가질 것으로 기대하기 때문입니다.

Chrome에서 소스를 보면 항상 그렇지는 않다는 것을 알 수 있습니다. 달력의 "1"요소를 "2"및 "3"과 비교하여 확인할 수 있습니다. "1"요소는 그 주위에 여러 요소가 있고 다른 요소는 그렇지 않음을 알 수 있습니다.

원래 XPath 쿼리가 요소를 반환하지 않으므로 오류가 발생합니다. HtmlAgilityPack에 대한 XPath 쿼리로 인해 DOM 요소가 발생하지 않으면 null을 반환합니다.

이제 전체 코드를 표시하지 않았으므로이 코드가 어떻게 실행되는지 알 수 없습니다. 그러나 모든 일정 항목을 반복하려고합니다. 그럼에도 불구하고 여러 가지 방법으로이 작업을 수행 할 수 있지만 descendant XPath 선택기를 사용하면 한 번에 많은 작업을 수행 할 수 있습니다 .

//div[@class='kal']//table//descendant::div[@class='cipars']

모든 일정 항목 (즉, 1 - 30)이 반환됩니다.

그러나 특정 행의 모든 ​​항목을 가져 오려면 해당 tr 을 쿼리에 사용하면됩니다.

//div[@class='kal']//table//descendant::div[@class='cipars']

이것은 2-8 (일정 항목의 두 번째 행)을 반환합니다.

특정 웹 사이트를 타겟팅하려면 웹 사이트의 소스 코드를 가정해야합니다. 모든 "cipars" div 에는 클래스 datums 이있는 td 의 조상이 있습니다. 그래서 질문에서 "3"값을 얻으려고합니다.

//div[@class='kal']//table//descendant::div[@class='cipars']

바라기를 이것은 적어도 문제를 보여주기에 충분합니다.

편집하다

XPath 문제가 있지만 다른 문제가 있습니다.

이 사이트는 매우 이상하게 만들어졌습니다. 달력이 이상한 방법으로로드됩니다. 해당 URL을 클릭하면 일정에 사용되는 전체 table 을 계산하는 XML 웹 서비스 (PHP로 작성)를 호출하는 일부 Javascript에 의해 일정이 만들어집니다.

사실 Javascript (클라이언트 측 코드)이므로 HtmlAgilityPack은이를 실행하지 않습니다. 따라서 HtmlAgilityPack은 테이블을 "보지"않습니다. 그러므로 그것에 대한 쿼리는 "찾을 수 없음"(null)으로 돌아옵니다.

1) 스크립트를 호출 할 도구를 사용하십시오. 이것으로, 나는 브라우저를로드하는 것을 의미합니다. 이것을 위해 사용하는 훌륭한 도구는 셀레늄 이라고합니다. 사이트에서 사용되는 모든 스크립팅이 실제로 호출되기 때문에이 방법이 더 나은 전체 솔루션 일 수 있습니다. XPath를 계속 사용할 수 있으므로 쿼리가 변경되지 않습니다.

두 번째 방법은 페이지 와 동일한 웹 서비스에 요청을 보내는 것입니다. 이것은 기본적으로 페이지가 가져 오는 HTML 과 동일한 HTML을 다시 가져와 HtmlAgilityPack에서 사용 하는 것 입니다. 어떻게해야합니까?

C #을 사용하여 데이터를 웹 서비스에 쉽게 게시 할 수 있습니다. 사용 편의성을 위해이 SO 질문 에서 코드를 도용했습니다. 이를 통해 페이지가 동일한 요청을 보내고 동일한 HTML을 다시 가져올 수 있습니다.

그래서 일부 POST 데이터를 보내려면 다음과 같은 메서드를 생성합니다 .....

//div[@class='kal']//table//descendant::div[@class='cipars']

우리는 그렇게 부를 수 있습니다.

//div[@class='kal']//table//descendant::div[@class='cipars']

나는 어떻게 이것을 얻었습니까? 우리가 호출하는 php 파일은 페이지가있는 웹 서비스이며 POST 데이터도 있습니다. 내가 서비스에 보내는 데이터를 발견 한 방법은 (자바의 개발자 콘솔을 사용하여) 자바 스크립트를 디버깅하는 것이지만 URL에있는 것과 거의 같은 것을 알 수 있습니다. 그건 의도적 인 것 같습니다.

responseBody 반환 단지의 물리적 HTML이다 table 달력합니다.

우리는 지금 그것을 어떻게합니까? 순수 HTML을 사용할 수 있기 때문에 HtmlAgilityPack에로드합니다.

//div[@class='kal']//table//descendant::div[@class='cipars']

자, 우리는 원래의 XPath를 다음과 같이 사용합니다.

//div[@class='kal']//table//descendant::div[@class='cipars']

이제, 우리는 "3"이 될 것으로 예상되는 것을 인쇄합니다 :

//div[@class='kal']//table//descendant::div[@class='cipars']

로컬로 실행하는 내 결과는 실제로 다음과 같습니다. 3 .

그러나이 방법으로 문제가 해결 될 수는 있지만 나머지 사이트는 이와 같은 것으로 가정합니다. 이 경우에도 위의 기술을 사용하여 문제를 해결할 수 있지만 Selenium과 같은 도구가 이러한 이유로 생성되었습니다.




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