mirror of
https://github.com/tiennm99/MTTools.git
synced 2026-10-20 00:15:39 +00:00
feat(go): rewrite in Go
This commit is contained in:
1 parent
6f854c6cd7
commit
e004d7237d
6 files changed
+248
-45
No files matched your search
+40
-12
@@ -1,6 +1,14 @@
|
|||||||
# crawl-prime
|
# crawl-prime
|
||||||
|
|
||||||
Crawl all prime available on http://compoasso.free.fr/primelistweb/page/prime/liste_online_en.php
|
Crawl all prime numbers available on http://compoasso.free.fr/primelistweb/page/prime/liste_online_en.php
|
||||||
|
|
||||||
|
*In 2025, I rewrite this project using Go. The Python version of this project can be found at [feature/python](https://github.com/tiennm99/crawl-prime/tree/feature/python) branch.*
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Go 1.18 or higher
|
||||||
|
- Internet connection to access the prime list website
|
||||||
|
- Write permissions in the current directory (for `primes.txt`)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -8,20 +16,40 @@ Crawl all prime available on http://compoasso.free.fr/primelistweb/page/prime/li
|
|||||||
```bash
|
```bash
|
||||||
git clone https://github.com/tiennm99/crawl-prime.git
|
git clone https://github.com/tiennm99/crawl-prime.git
|
||||||
cd crawl-prime
|
cd crawl-prime
|
||||||
|
|
||||||
2. Create a virtual environment:
|
|
||||||
```bash
|
|
||||||
python -m venv venv
|
|
||||||
source venv/bin/activate # On macOS/Linux
|
|
||||||
venv\Scripts\activate # On Windows
|
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Install the dependencies:
|
2. Install Go (if not already installed):
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
# Download and install Go from https://golang.org/dl/
|
||||||
```
|
# Or use your package manager:
|
||||||
|
# Ubuntu/Debian: sudo apt install golang
|
||||||
|
# macOS: brew install go
|
||||||
|
# Windows: Download from official website
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install dependencies:
|
||||||
|
```bash
|
||||||
|
go mod tidy
|
||||||
|
```
|
||||||
|
|
||||||
4. Run the script:
|
4. Run the script:
|
||||||
```bash
|
```bash
|
||||||
python main.py
|
go run main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The program will automatically:
|
||||||
|
- Start crawling from prime number 1
|
||||||
|
- Process pages in batches of 600 primes each
|
||||||
|
- Write all found primes to `primes.txt`
|
||||||
|
- Display progress information during execution
|
||||||
|
- Stop when it reaches 1,000,000 primes or encounters an error
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
- `primes.txt` - Contains all crawled prime numbers, one per line
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is for educational purposes. Please respect the terms of service of the prime list website.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
module github.com/tiennm99/crawl-prime
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
|
|
||||||
|
toolchain go1.24.10
|
||||||
|
|
||||||
|
require github.com/anaskhan96/soup v1.2.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/net v0.47.0 // indirect
|
||||||
|
golang.org/x/text v0.31.0 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
github.com/anaskhan96/soup v1.2.5 h1:V/FHiusdTrPrdF4iA1YkVxsOpdNcgvqT1hG+YtcZ5hM=
|
||||||
|
github.com/anaskhan96/soup v1.2.5/go.mod h1:6YnEp9A2yywlYdM4EgDz9NEHclocMepEtku7wg6Cq3s=
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
|
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anaskhan96/soup"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
targetURL = "http://compoasso.free.fr/primelistweb/page/prime/liste_online_en.php"
|
||||||
|
maxPrimes = 1000000
|
||||||
|
outputFile = "primes.txt"
|
||||||
|
perPageParam = "600"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
current := 0
|
||||||
|
totalWritten := 0
|
||||||
|
|
||||||
|
for current < maxPrimes {
|
||||||
|
fmt.Printf("Processing primes starting from: %d\n", current)
|
||||||
|
|
||||||
|
primes, nextCurrent, err := fetchPrimesPage(current)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error fetching page starting at %d: %v", current, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(primes) == 0 {
|
||||||
|
log.Printf("No primes found on page starting at %d", current)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write primes to file
|
||||||
|
err = writePrimesToFile(primes)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error writing primes to file: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
totalWritten += len(primes)
|
||||||
|
fmt.Printf("Wrote %d primes (total: %d)\n", len(primes), totalWritten)
|
||||||
|
|
||||||
|
if nextCurrent <= current {
|
||||||
|
log.Printf("Next current (%d) is not greater than current (%d), stopping", nextCurrent, current)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
current = nextCurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Completed! Total primes written: %d\n", totalWritten)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchPrimesPage(start int) ([]string, int, error) {
|
||||||
|
// Prepare form data
|
||||||
|
formData := url.Values{
|
||||||
|
"primePageInput": {perPageParam},
|
||||||
|
"numberInput": {strconv.Itoa(start)},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create request
|
||||||
|
req, err := http.NewRequest("POST", targetURL, strings.NewReader(formData.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Set("User-Agent", "Prime-Crawler/1.0")
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to send request: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, 0, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse HTML
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to read response body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsePrimesFromHTML(body, start)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePrimesFromHTML(htmlContent []byte, start int) ([]string, int, error) {
|
||||||
|
// Parse HTML using soup (similar to BeautifulSoup)
|
||||||
|
htmlStr := string(htmlContent)
|
||||||
|
doc := soup.HTMLParse(htmlStr)
|
||||||
|
|
||||||
|
// Find the first table (matching Python soup.find('table'))
|
||||||
|
table := doc.Find("table")
|
||||||
|
if table.Error != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to find table: %w", table.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find form within the table (matching Python table.find('form'))
|
||||||
|
form := table.Find("form")
|
||||||
|
if form.Error != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to find form: %w", form.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find inner table within the form (matching Python form.find('table'))
|
||||||
|
table1 := form.Find("table")
|
||||||
|
if table1.Error != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to find inner table: %w", table1.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all td elements (matching Python table1.find_all('td'))
|
||||||
|
tdElements := table1.FindAll("td")
|
||||||
|
if len(tdElements) == 0 {
|
||||||
|
return nil, 0, fmt.Errorf("no td elements found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract primes from all td elements except last 10 (matching Python td_elements[0:-10])
|
||||||
|
var primes []string
|
||||||
|
for i, td := range tdElements {
|
||||||
|
if i < len(tdElements)-10 {
|
||||||
|
text := strings.TrimSpace(td.Text())
|
||||||
|
if text != "" {
|
||||||
|
primes = append(primes, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get next current from the 11th element from the end (matching Python td_elements[-11])
|
||||||
|
var nextCurrent int
|
||||||
|
if len(tdElements) >= 11 {
|
||||||
|
nextTd := tdElements[len(tdElements)-11]
|
||||||
|
text := strings.TrimSpace(nextTd.Text())
|
||||||
|
if text != "" {
|
||||||
|
var err error
|
||||||
|
nextCurrent, err = strconv.Atoi(text)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to parse next current number: %w", err)
|
||||||
|
}
|
||||||
|
nextCurrent += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(primes) == 0 {
|
||||||
|
return nil, 0, fmt.Errorf("no primes found in HTML response")
|
||||||
|
}
|
||||||
|
|
||||||
|
return primes, nextCurrent, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writePrimesToFile(primes []string) error {
|
||||||
|
file, err := os.OpenFile(outputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open output file: %w", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
for _, prime := range primes {
|
||||||
|
_, err := file.WriteString(prime + "\n")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write prime to file: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import requests
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
url = "http://compoasso.free.fr/primelistweb/page/prime/liste_online_en.php"
|
|
||||||
max = 1_000_000
|
|
||||||
current = 0
|
|
||||||
|
|
||||||
while current < max:
|
|
||||||
data = {
|
|
||||||
"primePageInput": "600",
|
|
||||||
"numberInput": current,
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, data=data)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
soup = BeautifulSoup(response.text, 'html.parser')
|
|
||||||
table = soup.find('table')
|
|
||||||
if table:
|
|
||||||
form = table.find('form')
|
|
||||||
if form:
|
|
||||||
table1 = form.find('table')
|
|
||||||
if table1:
|
|
||||||
td_elements = table1.find_all('td')
|
|
||||||
output_file = "primes.txt"
|
|
||||||
|
|
||||||
with open(output_file, "a", encoding="utf-8") as file:
|
|
||||||
for td in td_elements[0:-10]:
|
|
||||||
file.write(td.text + "\n")
|
|
||||||
|
|
||||||
current = int(td_elements[-11].text) + 1
|
|
||||||
else:
|
|
||||||
print("Error - current: " + current)
|
|
||||||
Binary file not shown.
Reference in new issue
Block a user