Loading repository data…
Loading repository data…
skrapeit / repository
A Kotlin-based testing/scraping/parsing library providing the ability to analyze and extract data from HTML (server & client-side rendered). It places particular emphasis on ease of use and a high level of readability by providing an intuitive DSL. It aims to be a testing lib, but can also be used to scrape websites in a convenient fashion.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
| :bellhop_bell: :rotating_light: Help wanted :rotating_light: :bellhop_bell: |
|---|
| Looking for Co-Maintainer(s), please contact christian.draeger1@gmail.com if you are interested in helping to maintain and evolve skrape{it} :heart: |
skrape{it} is a Kotlin-based HTML/XML testing and web scraping library that can be used seamlessly in Spring-Boot, Ktor, Android or other Kotlin-JVM projects. The ability to analyze and extract HTML including client-side rendered DOM trees and all other XML-related markup specifications such as SVG, UML, RSS,... makes it unique. It places particular emphasis on ease of use and a high level of readability by providing an intuitive DSL. First and foremost skrape{it} aims to be a testing tool (not tied to a particular test runner), but it can also be used to scrape websites in a convenient fashion.
In addition, extensions for well-known testing libraries are provided to extend them with the mentioned skrape{it} functionality. Currently available:
You'll always find the latest documentation, release notes and examples regarding official releases at https://docs.skrape.it. The README file you are reading right now provides example related to the latest master. Just use it if you won't wait for latest changes to be released. If you don't want to read that much or just want to get a rough overview on how to use skrape{it}, you can have a look at the Documentation by Example section which refers to the current master.
All our official/stable releases will be published to mavens central repository.
dependencies {
implementation("it.skrape:skrapeit:1.2.2")
}
<dependency>
<groupId>it.skrape</groupId>
<artifactId>skrapeit</artifactId>
<version>1.2.2</version>
</dependency>
We are offering snapshot releases by publishing every successful build of a commit that has been pushed to master branch. Thereby you can just install the latest implementation of skrape{it}. Be careful since these are non-official releases and may be unstable as well as breaking changes can occur at any time.
repositories {
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
}
dependencies {
implementation("it.skrape:skrapeit:0-SNAPSHOT") { isChanging = true } // version number will stay - implementation may change ...
}
// optional
configurations.all {
resolutionStrategy {
cacheChangingModulesFor(0, "seconds")
}
}
<repositories>
<repository>
<id>snapshot</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
...
<dependency>
<groupId>it.skrape</groupId>
<artifactId>skrapeit</artifactId>
<version>0-SNAPSHOT</version>
</dependency>
You can find further examples in the projects integration tests.
We have a working Android sample using jetpack-compose in our example projects as living documentation.
@Test
fun `can read and return html from String`() {
htmlDocument("""
<html>
<body>
<h1>welcome</h1>
<div>
<p>first p-element</p>
<p class="foo">some p-element</p>
<p class="foo">last p-element</p>
</div>
</body>
</html>""") {
h1 {
findFirst {
text toBe "welcome"
}
}
p {
withClass = "foo"
findFirst {
text toBe "some p-element"
className toBe "foo"
}
}
p {
findAll {
text toContain "p-element"
}
findLast {
text toBe "last p-element"
}
}
}
}
}
data class MySimpleDataClass(
val httpStatusCode: Int,
val httpStatusMessage: String,
val paragraph: String,
val allParagraphs: List<String>,
val allLinks: List<String>
)
class HtmlExtractionService {
fun extract() {
val extracted = skrape(HttpFetcher) {
request {
url = "http://localhost:8080"
}
response {
MySimpleDataClass(
httpStatusCode = status { code },
httpStatusMessage = status { message },
allParagraphs = document.p { findAll { eachText } },
paragraph = document.p { findFirst { text } },
allLinks = document.a { findAll { eachHref } }
)
}
}
print(extracted)
// will print:
// MyDataClass(httpStatusCode=200, httpStatusMessage=OK, paragraph=i'm a paragraph, allParagraphs=[i'm a paragraph, i'm a second paragraph], allLinks=[http://some.url, http://some-other.url])
}
}
data class MyDataClass(
var httpStatusCode: Int = 0,
var httpStatusMessage: String = "",
var paragraph: String = "",
var allParagraphs: List<String> = emptyList(),
var allLinks: List<String> = emptyList()
)
class HtmlExtractionService {
fun extract() {
val extracted = skrape(HttpFetcher) {
request {
url = "http://localhost:8080"
}
extractIt<MyDataClass> {
it.httpStatusCode = statusCode
it.httpStatusMessage = statusMessage.toString()
htmlDocument {
it.allParagraphs = p { findAll { eachText }}
it.paragraph = p { findFirst { text }}
it.allLinks = a { findAll { eachHref }}
}
}
}
print(extracted)
// will print:
// MyDataClass(httpStatusCode=200, httpStatusMessage=OK, paragraph=i'm a paragraph, allParagraphs=[i'm a paragraph, i'm a second paragraph], allLinks=[http://some.url, http://some-other.url])
}
}
@Test
fun `dsl can skrape by url`() {
skrape(HttpFetcher) {
request {
url = "http://localhost:8080/example"
}
response {
htmlDocument {
// all official html and html5 elements are supported by the DSL
div {
withClass = "foo" and "bar" and "fizz" and "buzz"
findFirst {
text toBe "div with class foo"
// it's possible to search for elements from former search results
// e.g. search all matching span elements within the above div with class foo etc...
span {
findAll {
// do something
}
}
}
findAll {
toBePresentExactlyTwice
}
}
// can handle custom tags as well
"a-custom-tag" {
findFirst {
toBePresentExactlyOnce
text toBe "i'm a custom html5 tag"
text
}
}
// can handle custom tags written in css selctor query syntax
"div.foo.bar.fizz.buzz" {
findFirst {
text toBe "div with class foo"
}
}
// can handle custom tags and add selector specificas via DSL
"div.foo" {
withClass = "bar" and "fizz" and "buzz"
findFirst {
text toBe "div with class fo