-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Develop Product Hunt Parser #15
Comments
Sddilora
added
web scrap
Web scraping is required
research
Investigation or exploration of new concepts, techniques, or approaches
labels
May 15, 2024
Product Hunt provides an API, eliminating the need to parse the page. However, the request limit is quite restrictive. One potential solution is to store all team access tokens in an array, but this approach is not confirmed yet. |
currently working script ( get if the given users voted for the given product with access token) package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
const ACCESS_TOKEN = "" // fill with an access token
type User struct {
Username string `json:"username"`
UserID string `json:"userID"`
}
func main() {
productSlug := "multi-ai-chat" // This is just an example product slug, but this product really exists.
// Read users from JSON file
users, err := readUsersFromFile("users.json")
if err != nil {
fmt.Println("Error reading users:", err)
return
}
// Get product ID by slug
productID, err := getProductIDBySlug(productSlug)
if err != nil {
fmt.Println("Error getting product ID:", err)
return
}
// Check if users voted for the product
for _, user := range users {
voted, err := hasUserVoted(productID, user.UserID)
if err != nil {
fmt.Printf("Error checking if user %s voted: %v\n", user.Username, err)
continue
}
if voted {
fmt.Printf("User %s voted for the product.\n", user.Username)
} else {
fmt.Printf("User %s did not vote for the product.\n", user.Username)
}
}
}
func readUsersFromFile(filename string) ([]User, error) {
var users []User
file, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
err = json.Unmarshal(file, &users)
if err != nil {
return nil, err
}
return users, nil
}
func getProductIDBySlug(slug string) (string, error) {
query := map[string]string{
"query": fmt.Sprintf(`query { post(slug: "%s") { id } }`, slug),
}
queryJSON, err := json.Marshal(query)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", "https://api.producthunt.com/v2/api/graphql", bytes.NewBuffer(queryJSON))
if err != nil {
return "", err
}
req.Header.Set("Authorization", "Bearer "+ACCESS_TOKEN)
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var jsonResponse map[string]interface{}
if err := json.Unmarshal(body, &jsonResponse); err != nil {
return "", err
}
data, ok := jsonResponse["data"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("unexpected response format: missing data field")
}
post, ok := data["post"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("unexpected response format: missing post field")
}
productID, ok := post["id"].(string)
if !ok {
return "", fmt.Errorf("unexpected response format: missing product ID")
}
return productID, nil
}
func hasUserVoted(productID string, userID string) (bool, error) {
var cursor *string
for {
// Prepare the cursor clause if a cursor is available
cursorClause := ""
if cursor != nil {
cursorClause = fmt.Sprintf(`after: "%s", `, *cursor)
}
query := map[string]string{
"query": fmt.Sprintf(`query {
post(id: "%s") {
votes(%sfirst: 20) {
nodes {
userId
}
pageInfo {
endCursor
hasNextPage
}
}
}
}`, productID, cursorClause),
}
queryJSON, err := json.Marshal(query)
if err != nil {
return false, err
}
req, err := http.NewRequest("POST", "https://api.producthunt.com/v2/api/graphql", bytes.NewBuffer(queryJSON))
if err != nil {
return false, err
}
req.Header.Set("Authorization", "Bearer "+ACCESS_TOKEN)
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, err
}
var jsonResponse map[string]interface{}
if err := json.Unmarshal(body, &jsonResponse); err != nil {
return false, err
}
data, ok := jsonResponse["data"].(map[string]interface{})
if !ok {
return false, fmt.Errorf("unexpected response format: missing data field")
}
post, ok := data["post"].(map[string]interface{})
if !ok {
return false, fmt.Errorf("unexpected response format: missing post field")
}
votes, ok := post["votes"].(map[string]interface{})
if !ok {
return false, fmt.Errorf("unexpected response format: missing votes field")
}
nodes, ok := votes["nodes"].([]interface{})
if !ok {
return false, fmt.Errorf("unexpected response format: missing nodes field")
}
for _, node := range nodes {
if node.(map[string]interface{})["userId"] == userID {
return true, nil
}
}
pageInfo, ok := votes["pageInfo"].(map[string]interface{})
if !ok {
return false, fmt.Errorf("unexpected response format: missing pageInfo field")
}
hasNextPage, ok := pageInfo["hasNextPage"].(bool)
if !ok {
return false, fmt.Errorf("unexpected response format: missing hasNextPage field")
}
if !hasNextPage {
break
}
endCursor, ok := pageInfo["endCursor"].(string)
if !ok {
return false, fmt.Errorf("unexpected response format: missing endCursor field")
}
cursor = &endCursor
}
return false, nil
} users.json [
{
"userID": "7099447",
"username": "Semanur Guclu"
},
{
"userID": "6562454",
"username": "Dilara Doğan"
},
{
"userID": "9876542",
"username": "example_user2"
},
{
"userID": "7109434",
"username": "Ebrar Kesici"
}
] |
Here is an example result: User Semanur Guclu did not vote for the product.
User Dilara Doğan voted for the product.
User example_user2 did not vote for the product.
User Ebrar Kesici voted for the product. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Create a script to parse Product Hunt data in response to a new command (/productHuntStar) where a user can input a Product Hunt link. The script should retrieve information on who from our team has starred the product (which also requires retrieving our team's Product Hunt accounts as prerequisities), the total number of stars, and other relevant details.
The text was updated successfully, but these errors were encountered: