mirror of
https://codeberg.org/scip/kleingebaeck.git
synced 2025-12-16 20:11:01 +01:00
re-orgainzied code a little, using go templates instead format string
This commit is contained in:
21
README.md
21
README.md
@@ -67,6 +67,27 @@ The `XXXXX` part is your userid.
|
|||||||
Put it into the configfile as outlined above. Also specify an output
|
Put it into the configfile as outlined above. Also specify an output
|
||||||
directory. Then just execute `kleingebaeck`.
|
directory. Then just execute `kleingebaeck`.
|
||||||
|
|
||||||
|
Inside the output directory you'll find a new subdirectory for each
|
||||||
|
ad. Every directory contains a file `Adlisting.txt`, which will look
|
||||||
|
somewhat like this:
|
||||||
|
|
||||||
|
```default
|
||||||
|
Title: A book I sell
|
||||||
|
Price: 99 € VB
|
||||||
|
Id: 1919191919
|
||||||
|
Category: Sachbücher
|
||||||
|
Condition: Sehr Gut
|
||||||
|
Created: 10.12.2023
|
||||||
|
|
||||||
|
This is the description text.
|
||||||
|
|
||||||
|
Pay with paypal.
|
||||||
|
```
|
||||||
|
|
||||||
|
You can change the formatting using the `template` config
|
||||||
|
variable. The supplied sample config contains the default template.
|
||||||
|
|
||||||
|
All images will be stored in the same directory.
|
||||||
|
|
||||||
## Kleingebäck?
|
## Kleingebäck?
|
||||||
|
|
||||||
|
|||||||
11
config.go
11
config.go
@@ -22,6 +22,17 @@ import (
|
|||||||
"github.com/hashicorp/hcl/v2/hclsimple"
|
"github.com/hashicorp/hcl/v2/hclsimple"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
VERSION string = "0.0.4"
|
||||||
|
Baseuri string = "https://www.kleinanzeigen.de"
|
||||||
|
Listuri string = "/s-bestandsliste.html"
|
||||||
|
Defaultdir string = "."
|
||||||
|
DefaultTemplate string = "Title: {{.Title}}\nPrice: {{.Price}}\nId: {{.Id}}\n" +
|
||||||
|
"Category: {{.Category}}\nCondition: {{.Condition}}\nCreated: {{.Created}}\n\n{{.Text}}\n"
|
||||||
|
Useragent string = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||||
|
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Verbose bool `hcl:"verbose"`
|
Verbose bool `hcl:"verbose"`
|
||||||
User int `hcl:"user"`
|
User int `hcl:"user"`
|
||||||
|
|||||||
@@ -15,6 +15,5 @@ verbose = true
|
|||||||
outdir = "test"
|
outdir = "test"
|
||||||
|
|
||||||
# template. leave empty to use the default one, which is:
|
# template. leave empty to use the default one, which is:
|
||||||
# Title: %s\nPrice: %s\nId: %s\nCategory: %s\nCondition: %s\nCreated: %s\nBody:\n\n%s\n
|
# "Title: {{.Title}}\nPrice: {{.Price}}\nId: {{.Id}}\nCategory: {{.Category}}\nCondition: {{.Condition}}\nCreated: {{.Created}}\n\n{{.Text}}\n"
|
||||||
# take care to include exactly 7 times '%s'!
|
|
||||||
template = ""
|
template = ""
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
.\" ========================================================================
|
.\" ========================================================================
|
||||||
.\"
|
.\"
|
||||||
.IX Title "KLEINGEBAECK 1"
|
.IX Title "KLEINGEBAECK 1"
|
||||||
.TH KLEINGEBAECK 1 "2023-12-16" "1" "User Commands"
|
.TH KLEINGEBAECK 1 "2023-12-17" "1" "User Commands"
|
||||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||||
.\" way too many mistakes in technical documents.
|
.\" way too many mistakes in technical documents.
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
@@ -179,10 +179,11 @@ Format is simple:
|
|||||||
Be carefull if you want to change the template. The default one looks like this:
|
Be carefull if you want to change the template. The default one looks like this:
|
||||||
.PP
|
.PP
|
||||||
.Vb 1
|
.Vb 1
|
||||||
\& Title: %s\enPrice: %s\enId: %s\enCategory: %s\enCondition: %s\enCreated: %s\enBody:\en\en%s\en
|
\& Title: {{.Title}}\enPrice: {{.Price}}\enId: {{.Id}}\enCategory: {{.Category}}\enCondition: {{.Condition}}\enCreated: {{.Created}}\en\en{{.Text}}\en
|
||||||
.Ve
|
.Ve
|
||||||
.PP
|
.PP
|
||||||
If you change it, include 7 times the '%s' format tag.
|
You can left out certain fields and use any formatting you like. Refer
|
||||||
|
to <https://pkg.go.dev/text/template> for details how to write a template.
|
||||||
.SH "SETUP"
|
.SH "SETUP"
|
||||||
.IX Header "SETUP"
|
.IX Header "SETUP"
|
||||||
To setup the tool, you need to lookup your userid on
|
To setup the tool, you need to lookup your userid on
|
||||||
|
|||||||
@@ -39,9 +39,11 @@ CONFIGURATION
|
|||||||
Be carefull if you want to change the template. The default one looks
|
Be carefull if you want to change the template. The default one looks
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
Title: %s\nPrice: %s\nId: %s\nCategory: %s\nCondition: %s\nCreated: %s\nBody:\n\n%s\n
|
Title: {{.Title}}\nPrice: {{.Price}}\nId: {{.Id}}\nCategory: {{.Category}}\nCondition: {{.Condition}}\nCreated: {{.Created}}\n\n{{.Text}}\n
|
||||||
|
|
||||||
If you change it, include 7 times the '%s' format tag.
|
You can left out certain fields and use any formatting you like. Refer
|
||||||
|
to <https://pkg.go.dev/text/template> for details how to write a
|
||||||
|
template.
|
||||||
|
|
||||||
SETUP
|
SETUP
|
||||||
To setup the tool, you need to lookup your userid on kleinanzeigen.de.
|
To setup the tool, you need to lookup your userid on kleinanzeigen.de.
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ Format is simple:
|
|||||||
|
|
||||||
Be carefull if you want to change the template. The default one looks like this:
|
Be carefull if you want to change the template. The default one looks like this:
|
||||||
|
|
||||||
Title: %s\nPrice: %s\nId: %s\nCategory: %s\nCondition: %s\nCreated: %s\nBody:\n\n%s\n
|
Title: {{.Title}}\nPrice: {{.Price}}\nId: {{.Id}}\nCategory: {{.Category}}\nCondition: {{.Condition}}\nCreated: {{.Created}}\n\n{{.Text}}\n
|
||||||
|
|
||||||
If you change it, include 7 times the '%s' format tag.
|
You can left out certain fields and use any formatting you like. Refer
|
||||||
|
to L<https://pkg.go.dev/text/template> for details how to write a template.
|
||||||
|
|
||||||
=head1 SETUP
|
=head1 SETUP
|
||||||
|
|
||||||
|
|||||||
8
main.go
8
main.go
@@ -28,14 +28,6 @@ import (
|
|||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
const VERSION string = "0.0.3"
|
|
||||||
const Useragent string = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
|
||||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
||||||
const Baseuri string = "https://www.kleinanzeigen.de"
|
|
||||||
const Listuri string = "/s-bestandsliste.html"
|
|
||||||
const Defaultdir string = "."
|
|
||||||
const DefaultTemplate string = "Title: %s\nPrice: %s\nId: %s\nCategory: %s\nCondition: %s\nCreated: %s\nBody:\n\n%s\n"
|
|
||||||
|
|
||||||
const Usage string = `This is kleingebaeck, the kleinanzeigen.de backup tool.
|
const Usage string = `This is kleingebaeck, the kleinanzeigen.de backup tool.
|
||||||
Usage: kleingebaeck [-dvVhmoc] [<ad-listing-url>,...]
|
Usage: kleingebaeck [-dvVhmoc] [<ad-listing-url>,...]
|
||||||
Options:
|
Options:
|
||||||
|
|||||||
29
scrape.go
29
scrape.go
@@ -23,7 +23,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -160,28 +159,12 @@ func Scrape(uri string, dir string, template string) error {
|
|||||||
}
|
}
|
||||||
slog.Debug("extracted ad listing", "ad", ad)
|
slog.Debug("extracted ad listing", "ad", ad)
|
||||||
|
|
||||||
// prepare output dir
|
// write listing
|
||||||
dir = dir + "/" + ad.Slug
|
err = WriteAd(dir, ad, template)
|
||||||
err = Mkdir(dir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// write ad file
|
|
||||||
listingfile := strings.Join([]string{dir, "Adlisting.txt"}, "/")
|
|
||||||
f, err := os.Create(listingfile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ad.Text = strings.ReplaceAll(ad.Text, "<br/>", "\n")
|
|
||||||
_, err = fmt.Fprintf(f, template,
|
|
||||||
ad.Title, ad.Price, ad.Id, ad.Category, ad.Condition, ad.Created, ad.Text)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slog.Info("wrote ad listing", "listingfile", listingfile)
|
|
||||||
|
|
||||||
return ScrapeImages(dir, ad)
|
return ScrapeImages(dir, ad)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,13 +213,7 @@ func Getimage(uri, fileName string) error {
|
|||||||
return errors.New("received non 200 response code")
|
return errors.New("received non 200 response code")
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.Create(fileName)
|
err = WriteImage(fileName, response.Body)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(file, response.Body)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
72
store.go
Normal file
72
store.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
Copyright © 2023 Thomas von Dein
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
tpl "text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WriteAd(dir string, ad *Ad, template string) error {
|
||||||
|
// prepare output dir
|
||||||
|
dir = dir + "/" + ad.Slug
|
||||||
|
err := Mkdir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write ad file
|
||||||
|
listingfile := strings.Join([]string{dir, "Adlisting.txt"}, "/")
|
||||||
|
f, err := os.Create(listingfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ad.Text = strings.ReplaceAll(ad.Text, "<br/>", "\n")
|
||||||
|
|
||||||
|
tmpl, err := tpl.New("adlisting").Parse(template)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tmpl.Execute(f, ad)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("wrote ad listing", "listingfile", listingfile)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteImage(filename string, reader io.ReadCloser) error {
|
||||||
|
file, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(file, reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user