Why does the example from official docs of skrape{it} not compile - html

There is example piece of code from official website of skrape{it}. It is about extracting data from website. I'm using library version 1.0.0-alpha6
import it.skrape.core.htmlDocument
import it.skrape.selects.and
import it.skrape.selects.eachImage
import it.skrape.selects.eachText
import it.skrape.selects.html5.a
import it.skrape.selects.html5.div
import it.skrape.selects.html5.p
import it.skrape.selects.html5.span
import org.junit.jupiter.api.Test
// just some object where we will store our scraped data
data class MyExtractedData(
var httpMessage: String = "",
var userName: String = "",
var repositoryNames: List<String> = emptyList(),
var theThirdRepositoriesName: String = "",
var firstThreeHrefs: List<String> = emptyList(),
var overviewLink: String = "",
var firstThreeImageSources: List<String> = emptyList(),
var title: String = "",
var starsCount: String = ""
)
fun main() {
val extracted = skrape { // 1️⃣
url = "https://github.com/skrapeit"
extractIt<MyExtractedData> { it ->
it.httpMessage = status { message } // 2️⃣
htmlDocument { // 3️⃣
relaxed = true // 4️⃣
it.userName = ".h-card .p-nickname" { findFirst { text } } // 5️⃣
val repositories = span(".repo") { findAll { this }} // 6️⃣
println("hello world") // 7️⃣
it.repositoryNames = repositories.filter { it.text.contains("skrape") }.eachText // 8️⃣
it.theThirdRepositoriesName = span(".repo") {
2 { text } // 9️⃣
}
it.firstThreeImageSources = findAll { eachImage.map { image -> image.value } }.take(3) // 1️⃣0️⃣
it.firstThreeHrefs = findAll { eachHref }.take(3) // 1️⃣1️⃣
it.overviewLink = findAll { eachLink["Overview"] ?: "not found" } // 1️⃣2️⃣
it.title = titleText // 1️⃣3️⃣
// *️⃣
it.starsCount = div { // 1️⃣5️⃣
withClass = "pinned-item-list-item"
findFirst {
p { // 1️⃣6️⃣
findSecond {
a {
// 1️⃣7️⃣
withClass = "pinned-item-meta" and "muted-link" // 1️⃣8️⃣
withAttribute = "href" to "/skrapeit/skrape.it/stargazers" // 1️⃣9️⃣
findFirst {
ownText
}
}
}
}
}
}
}
}
}
println(extracted)
}
This piece of code simply does not compile. All possible imports had been done.
Errors:
Unresolved reference: status
Unresolved reference: message
Unresolved reference: relaxed
Function invocation 'eachText()' expected (line with 8️⃣ comment)
Expression '2' of type 'Int' cannot be invoked as a function. The function 'invoke()' is not found (line with 9️⃣ comment)
Type mismatch. Required: List. Found: List (line with 1️⃣0️⃣ comment)
And that's not all. There are lots of errors almost in every line. Where is the mistake?
Thank you!

I know I has been a while, but I was looking at the scrape{it} yesterday for the first time and face the same issue as you did.
The guys have an error on the official docs (probably it is just a way it used to work before).
To make it work, you need to change the top of the function slightly:
val extracted = skrape(HttpFetcher) { // 1️⃣
request {
url = "https://github.com/skrapeit"
}
It did a trick for me, hope will help someone as well.

Related

How to retrieve entire Logger output?

I have large sets of data (mainly arrays and objects with many elements) and I am trying to log out the entire result to check for bugs. However, in some cases it says "Logging output too large. Truncating output." Where can I see the output in its entirety? I am working with Map Objects and trying to debug why my calculations don't match Google's output.
Logger.log is limited to the number of lines that it can contain. However you can make your own logger and save it to a text file.
var Log = null;
function testLogger() {
try {
Log = new LogFile("testLogFile");
test1();
test2();
throw "done"
}
catch(err) {
Log.log(err);
Log.save();
}
}
function test1() {
Log.log("in test1");
}
function test2() {
Log.log("in test2");
}
class LogFile {
constructor (name) {
if( name === undefined ) name = "_LogFile"
this.name = name;
this.text = [];
}
log(text) {
this.text.push(text);
}
save() {
try {
let text = "";
this.text.forEach( line => text = text.concat(line,"\n") );
let files = DriveApp.getFilesByName(this.name);
let file = null;
if( files.hasNext() ) {
file = files.next();
file.setContent(text);
}
else {
DriveApp.createFile(this.name,text);
}
}
catch(err) {
Logger.log(err);
}
}
}
The text file is shown below.

how to handle enum type with json2typescript

I receive a JSON from the back-end that contains an Enum type.
{
...,
pst:['SMS','EMAIL'],
...
}
This is my Typescript enum class:
export enum PostSynchroActions {
SMS = 'SMS',
Email = 'Email',
SocialWall = 'SocialWall',
Transformation = 'Transformation',
Clone = 'Clone'
}
How can I De-serialize this with json2Typescript library.
This is my line for the typescript class that I use to de-serialize the back-end json.
export class Terminal {
...
#JsonProperty('pst',[PostSynchroActions])
actionPostSynchro:PostSynchroActions[] = [];
...
}
You can use PostSynchroActions[data] if you are sending the keys, otherwise just use data as PostSynchroActions. You also need to check for EMAIL to equal Email so the full function would be:
export enum PostSynchroActions {
SMS = 'SMS',
Email = 'Email',
SocialWall = 'SocialWall',
Transformation = 'Transformation',
Clone = 'Clone'
}
function postSynchroActionsFromKeys(data: string) {
if(data === "EMAIL") {
data = "Email";
}
return PostSynchroActions[data as PostSynchroActions] as PostSynchroActions;
}
function postSynchroActionsFromValues(data: string) {
if(data === "EMAIL") {
data = "Email";
}
return data as PostSynchroActions;
}
Playground

How to load json from file and set it as global variable in Vue?

I'm new to Vue. I want to read employeeId from a login form and ust it to load some json files named according as employeeId.json like (10000001.json, 20000001.json) and set the json object as a global variable so I can easily access it in all components.
Firstly, I don't know how to dynamically load json files. Using import sees not work. Some one suggested using require should work. But there are not many examples, I don't know where to put require...
Secondly, how do I set the json as global after the employeeId props in? I'm very confused where to put it (inside the export default or not? inside methods or not? or inside created/mounted or not?) and where to use this or not...
This is the script section of my headerNav.vue file.
<script>
//**I placed them here now, it works, but employeeId is hard coded...
import json10000001 from "./json/10000001.json";
import json20000001 from "./json/20000001.json";
import json30000001 from "./json/30000001.json";
// var employeeId = employeeIdFromLogin;
var jsonForGlobal;
var employeeId = 10000001;
var jsonFileCurrentObj;
if (employeeId == "10000001") {
jsonForGlobal = jsonFileCurrentObj = json10000001;
} else if (employeeId == "20000001") {
jsonForGlobal = jsonFileCurrentObj = json20000001;
} else if (employeeId == "30000001") {
jsonForGlobal = jsonFileCurrentObj = json30000001;
}
export default {
// props:{
// employeeIdFromLogin: String,
// },
props:['employeeIdFromLogin'],
jsonForGlobal,
// employeeIdFromLogin,
data() {
return {
docked: false,
open: false,
position: "left",
userinfo: {},
jsonFileCurrent: jsonFileCurrentObj,
// employeeIdFromLogin: this.GLOBAL3.employeeIdFromLogin
// jsonFile: currentJsonFile
};
},
mounted() {
//**I tried put it here, not working well...
// var employeeId = this.employeeIdFromLogin;
// // var jsonForGlobal;
// console.log("headernav.employeeIdFromLogin="+this.employeeIdFromLogin);
// // var employeeId = 10000001;
// var jsonFileCurrentObj;
// if (employeeId == "10000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json10000001;
// } else if (employeeId == "20000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json20000001;
// } else if (employeeId == "30000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json30000001;
// }
},
methods: {
switchPage(pageName) {
this.$emit("switchPage", pageName);
}
//**I don't know how to use the require...
// var employeeId = 10000001;
// getJsonFile(employeeId) {
// this.currentJsonFile = require("../assets/json/" + employeeId + ".json");
// }
}
};
You might want to use vuex to manage global store. But if you don't want includes Vuex, there is a simpler way to have global state:
Define globalStore.js
// globalStore.js
export const globalStore = new Vue({
data: {
jsonForGlobal: null
}
})
then import it and use in component:
import {globalStore} from './globalStore.js'
export default {
props: ['employeeIdFromLogin'],
data: function ()
return {
jsonLocal: globalStore.jsonForGlobal,
jsonFileCurrent: null
}
},
watch: {
employeeIdFromLogin: {
handler(newVal, oldVal) {
const data = require('./json/' + this.employeeIdFromLogin + '.json')
this.jsonFileCurrent = data
globalStore.jsonForGlobal = data
}
}
}
}

How to use google.maps.geometry.encoding.decodePath in dartlang?

How is the way to use the function to decode a string?
I can not find the way with the native library
var path = google.maps.geometry.encoding.decodePath(encodedStr);
----- Soluction ----
String str = "ern[pd_cMiAa#\q#l#kAPY`Ad#hCnAr#^HOzAaClCgElBsCfBhA";
var decodedPath = encoding.decodePath(str);
var estimate_line = new Polyline(new PolylineOptions()
..path = decodedPath
..geodesic = true
..strokeColor = '#FF0000'
..strokeOpacity = 1.0
..strokeWeight = 2
..map = map
);
Here i have implemented in native dart
For encoding reference : https://developers.google.com/maps/documentation/utilities/polylinealgorithm Here the encoding algorithm is explained
import 'dart:io';
main()
{
var z="eo~fMzva{Fl|cuTgh~oU~bxjDhpptb#";
print(decode(z));
}
/** function to decode the string ****/
List decode(var a)
{
var list=a.codeUnits;
var lList=new List();
int index=0;
int len=a.length;
int c=0;
// repeating until all attributes are decoded
do
{
var shift=0;
int result=0;
// for decoding value of one attribute
do
{
c=list[index]-63;
result|=(c & 0x1F)<<(shift*5);
index++;
shift++;
}while(c>=32);
/* if value is negetive then bitwise not the value */
if(result & 1==1)
{
result=~result;
}
var result1 = (result >> 1) * 0.00001;
lList.add(result1);
}while(index<len);
/*adding to previous value as done in encoding */
for(var i=2;i<lList.length;i++)
lList[i]+=lList[i-2];
return lList;
}
With the google_maps package you can import package:google_maps/google_maps_encoding.dart and use encoding.decodePath(path). encoding is an optional js library you need to optin with http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=encoding in your <script>.
See the example with encoding library.
You can use the geo package to encode/decode path:
import 'package:geo/geo.dart';
void main() {
var decodedPath = const PolylineCodec().decode(str);
}

How to convert a json to a typescript interface?

Given a JSON output of an api:
{
"id": 13,
"name": "horst",
"cars": [{
"brand": "VW",
"maxSpeed": 120,
"isWastingGazoline": true
}]
}
I would like to define interfaces for typescript:
export interface Car {
brand: string;
maxSpeed: number;
isWastingGazoline: boolean;
}
export interface RaceCarDriver {
id: number;
name: string;
cars: Car[];
}
Yet I don't want them to type them manually, I rather have a script generate them for me.
How can I convert json into typescript interfaces? I also don't want to use webservices like MakeTypes or json2ts.
You can write the script using typescript compiler API and its ability to infer types. I was really surprised how easy it was.
You have to wrap your sample data to make it compile-able as typescript code. The script will pick all variable declarations and try to print inferred types for them. It uses variable names and property names for assigning names to types, and if two objects have a property with the same name, it will pick the type from the first one. So it will not work in case these types are actually different (the fix is left as an exercise). For your JSON output, the data sample will look like
file sample.ts
let raceCarDriver = {
"id": 13,
"name": "horst",
"cars": [{
"brand": "VW",
"maxSpeed": 120,
"isWastingGazoline": true,
}]
};
The script was tested with Typescript 2.1 (just released):
npm i typescript
npm i #types/node
./node_modules/.bin/tsc --lib es6 print-inferred-types.ts
node print-inferred-types.js sample.ts
output:
export interface RaceCarDriver {
id: number;
name: string;
cars: Car[];
}
export interface Car {
brand: string;
maxSpeed: number;
isWastingGazoline: boolean;
}
Here is the script: print-inferred-types.ts:
import * as ts from "typescript";
let fileName = process.argv[2];
function printInferredTypes(fileNames: string[], options: ts.CompilerOptions): void {
let program = ts.createProgram(fileNames, options);
let checker = program.getTypeChecker();
let knownTypes: {[name: string]: boolean} = {};
let pendingTypes: {name: string, symbol: ts.Symbol}[] = [];
for (const sourceFile of program.getSourceFiles()) {
if (sourceFile.fileName == fileName) {
ts.forEachChild(sourceFile, visit);
}
}
while (pendingTypes.length > 0) {
let pendingType = pendingTypes.shift();
printJsonType(pendingType.name, pendingType.symbol);
}
function visit(node: ts.Node) {
if (node.kind == ts.SyntaxKind.VariableStatement) {
(<ts.VariableStatement>node).declarationList.declarations.forEach(declaration => {
if (declaration.name.kind == ts.SyntaxKind.Identifier) {
let identifier = <ts.Identifier>declaration.name;
let symbol = checker.getSymbolAtLocation(identifier);
if (symbol) {
let t = checker.getTypeOfSymbolAtLocation(symbol, identifier);
if (t && t.symbol) {
pendingTypes.push({name: identifier.text, symbol: t.symbol});
}
}
}
});
}
}
function printJsonType(name: string, symbol: ts.Symbol) {
if (symbol.members) {
console.log(`export interface ${capitalize(name)} {`);
Object.keys(symbol.members).forEach(k => {
let member = symbol.members[k];
let typeName = null;
if (member.declarations[0]) {
let memberType = checker.getTypeOfSymbolAtLocation(member, member.declarations[0]);
if (memberType) {
typeName = getMemberTypeName(k, memberType);
}
}
if (!typeName) {
console.log(`// Sorry, could not get type name for ${k}!`);
} else {
console.log(` ${k}: ${typeName};`);
}
});
console.log(`}`);
}
}
function getMemberTypeName(memberName: string, memberType: ts.Type): string | null {
if (memberType.flags == ts.TypeFlags.String) {
return 'string';
} else if (memberType.flags == ts.TypeFlags.Number) {
return 'number';
} else if (0 !== (memberType.flags & ts.TypeFlags.Boolean)) {
return 'boolean';
} else if (memberType.symbol) {
if (memberType.symbol.name == 'Array' && (<ts.TypeReference>memberType).typeArguments) {
let elementType = (<ts.TypeReference>memberType).typeArguments[0];
if (elementType && elementType.symbol) {
let elementTypeName = capitalize(stripS(memberName));
if (!knownTypes[elementTypeName]) {
knownTypes[elementTypeName] = true;
pendingTypes.push({name: elementTypeName, symbol: elementType.symbol});
}
return `${elementTypeName}[]`;
}
} else if (memberType.symbol.name == '__object') {
let typeName = capitalize(memberName);
if (!knownTypes[typeName]) {
knownTypes[typeName] = true;
pendingTypes.push({name: typeName, symbol: memberType.symbol});
}
return typeName;
} else {
return null;
}
} else {
return null;
}
}
function capitalize(n: string) {
return n.charAt(0).toUpperCase() + n.slice(1);
}
function stripS(n: string) {
return n.endsWith('s') ? n.substring(0, n.length - 1) : n;
}
}
printInferredTypes([fileName], {
noEmitOnError: true, noImplicitAny: true,
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
});
Found a npm package that converts a arbitrary JSON file without a schema into a TS interface:
https://www.npmjs.com/package/json-to-ts
The author also provided a VSCode plugin.
You can use an npm module instead of the web hosted solution:
https://www.npmjs.com/package/json-schema-to-typescript
If your JSON comes from an HTTP API and the API has an swagger code definition, you can generate a TypeScript client:
https://github.com/swagger-api/swagger-codegen#api-clients
If you json comes from a Java ot .Net backened, you can generate TypeScript from Java or C# classes:
http://type.litesolutions.net
https://github.com/raphaeljolivet/java2typescript
Using only sed and tsc
sed '1s#^#const foo = #' sample.json > sample.$$.ts
tsc sample.$$.ts --emitDeclarationOnly --declaration
Append const foo = to beginning of file
Using sed to replace (s) nothing (#^#) at the beginning of the first line (1) with const foo =
output to sample.$$.ts
the extension is the required to be .ts
$$ expands to the shells process id, handy for a temp file that is unlikely to overwrite stuff you care about
ask tsc to only emit a .d.ts typings file
this file has pretty much everything you want for the interface. You might need to replace a few strings and customize it in a way you want but most of the leg work is done