@@ -17,12 +17,19 @@ const annoyingPromptUrls = [
17
17
"https://www.gjopen.com/questions/1779-are-there-any-forecasting-tips-tricks-and-experiences-you-would-like-to-share-and-or-discuss-with-your-fellow-forecasters" ,
18
18
"https://www.gjopen.com/questions/2246-are-there-any-forecasting-tips-tricks-and-experiences-you-would-like-to-share-and-or-discuss-with-your-fellow-forecasters-2022-thread" ,
19
19
"https://www.gjopen.com/questions/2237-what-forecasting-questions-should-we-ask-what-questions-would-you-like-to-forecast-on-gjopen" ,
20
+ "https://www.gjopen.com/questions/2437-what-forecasting-questions-should-we-ask-what-questions-would-you-like-to-forecast-on-gjopen"
20
21
] ;
21
22
const DEBUG_MODE : "on" | "off" = "off" ; // "on"
22
23
const id = ( ) => 0 ;
23
24
24
25
/* Support functions */
25
26
27
+ function cleanDescription ( text : string ) {
28
+ let md = toMarkdown ( text ) ;
29
+ let result = md . replaceAll ( "---" , "-" ) . replaceAll ( " " , " " ) ;
30
+ return result ;
31
+ }
32
+
26
33
async function fetchPage ( page : number , cookie : string ) {
27
34
const response : string = await axios ( {
28
35
url : htmlEndPoint + page ,
@@ -40,82 +47,68 @@ async function fetchStats(questionUrl: string, cookie: string) {
40
47
url : questionUrl + "/stats" ,
41
48
method : "GET" ,
42
49
headers : {
50
+ "Content-Type" : "text/html" ,
43
51
Cookie : cookie ,
44
52
Referer : questionUrl ,
45
53
} ,
46
54
} ) . then ( ( res ) => res . data ) ;
47
- //console.log(response)
48
55
49
- // Is binary?
50
- let isbinary = response . includes ( "binary?":true" ) ;
56
+ if ( response . includes ( "Sign up or sign in to forecast" ) ) {
57
+ throw Error ( "Not logged in" ) ;
58
+ }
59
+ // Init
60
+ let options : FullQuestionOption [ ] = [ ] ;
51
61
52
- let options : FetchedQuestion [ "options" ] = [ ] ;
53
- if ( isbinary ) {
54
- // Crowd percentage
55
- let htmlElements = response . split ( "\n" ) ;
56
- let h3Element = htmlElements . filter ( ( str ) => str . includes ( "<h3>" ) ) [ 0 ] ;
57
- // console.log(h3Element)
58
- let crowdpercentage = h3Element . split ( ">" ) [ 1 ] . split ( "<" ) [ 0 ] ;
59
- let probability = Number ( crowdpercentage . replace ( "%" , "" ) ) / 100 ;
60
- options . push (
61
- {
62
- name : "Yes" ,
63
- probability : probability ,
64
- type : "PROBABILITY" ,
65
- } ,
66
- {
67
- name : "No" ,
68
- probability : + ( 1 - probability ) . toFixed ( 2 ) , // avoids floating point shenanigans
69
- type : "PROBABILITY" ,
70
- }
71
- ) ;
72
- } else {
73
- let optionsHtmlElement = "<table" + response . split ( "tbody" ) [ 1 ] + "table>" ;
74
- let tablesAsJson = Tabletojson . convert ( optionsHtmlElement ) ;
75
- let firstTable = tablesAsJson [ 0 ] ;
76
- options = firstTable . map ( ( element : any ) => ( {
77
- name : element [ "0" ] ,
78
- probability : Number ( element [ "1" ] . replace ( "%" , "" ) ) / 100 ,
62
+ // Parse the embedded json
63
+ let htmlElements = response . split ( "\n" ) ;
64
+ let jsonLines = htmlElements . filter ( ( element ) =>
65
+ element . includes ( "data-react-props" )
66
+ ) ;
67
+ let embeddedJsons = jsonLines . map ( ( jsonLine , i ) => {
68
+ let innerJSONasHTML = jsonLine . split ( 'data-react-props="' ) [ 1 ] . split ( '"' ) [ 0 ] ;
69
+ let json = JSON . parse ( innerJSONasHTML . replaceAll ( """ , '"' ) ) ;
70
+ return json ;
71
+ } ) ;
72
+ let firstEmbeddedJson = embeddedJsons [ 0 ] ;
73
+ let title = firstEmbeddedJson . question . name ;
74
+ let description = cleanDescription ( firstEmbeddedJson . question . description ) ;
75
+ let comments_count = firstEmbeddedJson . question . comments_count ;
76
+ let numforecasters = firstEmbeddedJson . question . predictors_count ;
77
+ let numforecasts = firstEmbeddedJson . question . prediction_sets_count ;
78
+ let questionType = firstEmbeddedJson . question . type ;
79
+ if (
80
+ questionType . includes ( "Binary" ) ||
81
+ questionType . includes ( "NonExclusiveOpinionPoolQuestion" ) ||
82
+ questionType . includes ( "Forecast::Question" ) ||
83
+ ! questionType . includes ( "Forecast::MultiTimePeriodQuestion" )
84
+ ) {
85
+ options = firstEmbeddedJson . question . answers . map ( ( answer : any ) => ( {
86
+ name : answer . name ,
87
+ probability : answer . normalized_probability ,
79
88
type : "PROBABILITY" ,
80
89
} ) ) ;
81
- //console.log(optionsHtmlElement)
82
- //console.log(options)
90
+ if ( options . length == 1 && options [ 0 ] . name == "Yes" ) {
91
+ let probabilityNo =
92
+ options [ 0 ] . probability > 1
93
+ ? 1 - options [ 0 ] . probability / 100
94
+ : 1 - options [ 0 ] . probability ;
95
+ options . push ( {
96
+ name : "No" ,
97
+ probability : probabilityNo ,
98
+ type : "PROBABILITY" ,
99
+ } ) ;
100
+ }
83
101
}
84
-
85
- // Description
86
- let descriptionraw = response . split (
87
- `<div id="question-background" class="collapse smb">`
88
- ) [ 1 ] ;
89
- let descriptionprocessed1 = descriptionraw . split ( `</div>` ) [ 0 ] ;
90
- let descriptionprocessed2 = toMarkdown ( descriptionprocessed1 ) ;
91
- let descriptionprocessed3 = descriptionprocessed2
92
- . split ( "\n" )
93
- . filter ( ( string ) => ! string . includes ( "Confused? Check our" ) )
94
- . join ( "\n" ) ;
95
- let description = descriptionprocessed3 ;
96
-
97
- // Number of forecasts
98
- let numforecasts = response
99
- . split ( "prediction_sets_count":" ) [ 1 ]
100
- . split ( "," ) [ 0 ] ;
101
- //console.log(numforecasts)
102
-
103
- // Number of predictors
104
- let numforecasters = response
105
- . split ( "predictors_count":" ) [ 1 ]
106
- . split ( "," ) [ 0 ] ;
107
- //console.log(numpredictors)
108
-
109
102
let result = {
110
- description,
111
- options,
103
+ description : description ,
104
+ options : options ,
112
105
qualityindicators : {
113
106
numforecasts : Number ( numforecasts ) ,
114
107
numforecasters : Number ( numforecasters ) ,
108
+ comments_count : Number ( comments_count ) ,
115
109
} ,
116
- // this mismatches the code below, and needs to be fixed, but I'm doing typescript conversion and don't want to touch any logic for now
117
- } as any ;
118
-
110
+ } ;
111
+ // console.log(JSON.stringify(result, null, 4));
119
112
return result ;
120
113
}
121
114
@@ -150,6 +143,7 @@ async function goodjudgmentopen_inner(cookie: string) {
150
143
let results = [ ] ;
151
144
let init = Date . now ( ) ;
152
145
// console.log("Downloading... This might take a couple of minutes. Results will be shown.")
146
+ console . log ( "Page #1" )
153
147
while ( ! reachedEnd ( response ) && isSignedIn ( response ) ) {
154
148
let htmlLines = response . split ( "\n" ) ;
155
149
DEBUG_MODE == "on" ? htmlLines . forEach ( ( line ) => console . log ( line ) ) : id ( ) ;
@@ -187,6 +181,8 @@ async function goodjudgmentopen_inner(cookie: string) {
187
181
if ( j % 30 == 0 || DEBUG_MODE == "on" ) {
188
182
console . log ( `Page #${ i } ` ) ;
189
183
console . log ( question ) ;
184
+ } else {
185
+ console . log ( question . title )
190
186
}
191
187
// console.log(question)
192
188
results . push ( question ) ;
0 commit comments