Golang新手求助:实现服务器*.csv下载与表单提交后页面解析
Hey there! Let's tackle your two technical needs one by one, with practical code examples tailored for a Go beginner.
I'll cover two common scenarios here—pick the one that fits your use case:
Scenario A: Serve CSV for User Download via Web Endpoint
Create an HTTP endpoint that lets users download a CSV file stored on your server:
package main import ( "net/http" "os" ) func downloadCSVHandler(w http.ResponseWriter, r *http.Request) { // Update this path to your actual CSV file location on the server csvFilePath := "./your-data/file.csv" // Open the file file, err := os.Open(csvFilePath) if err != nil { http.Error(w, "CSV file not found", http.StatusNotFound) return } defer file.Close() // Set headers to trigger browser download w.Header().Set("Content-Disposition", "attachment; filename=\"exported-data.csv\"") w.Header().Set("Content-Type", "text/csv") // Stream the file to the response http.ServeFile(w, r, csvFilePath) } func main() { http.HandleFunc("/download-csv", downloadCSVHandler) // Start server on port 8080 http.ListenAndServe(":8080", nil) }
Users can now download the CSV by visiting http://your-server:8080/download-csv.
Scenario B: Programmatically Download CSV from Your Server to Local
If your Go app needs to fetch a CSV from your server and save it locally:
package main import ( "io" "net/http" "os" ) func fetchCSVFromServer() error { // Replace with your server's CSV endpoint csvURL := "http://your-server:8080/download-csv" resp, err := http.Get(csvURL) if err != nil { return err } defer resp.Body.Close() // Create local file to save the CSV localFile, err := os.Create("local-copy.csv") if err != nil { return err } defer localFile.Close() // Copy the server response to the local file _, err = io.Copy(localFile, resp.Body) return err } func main() { if err := fetchCSVFromServer(); err != nil { panic(err) // Replace with proper error handling in production } }
First, install the required package:
go get github.com/tebeka/selenium
You'll also need to download ChromeDriver (match the version to your installed Chrome browser) and place it in your project directory.
Here's a complete example that handles form submission, launches a headless Chrome session, logs in, and parses the target page:
package main import ( "fmt" "net/http" "text/template" "github.com/tebeka/selenium" "github.com/tebeka/selenium/chrome" ) // HTML template for your form (includes result display) const formHTML = ` <form action="/" method='POST'> Enter credentials:<br> Login: <input type="text" name="login" required> <br> Password: <input type="password" name="password" required> <br> Search link:<br> <input type="text" name="link" required> <br> <input type="submit" value="Submit"> </form> {{if .Result}} <h3>Parse Result:</h3> <p>{{.Result}}</p> {{end}} ` func main() { // Handle form requests http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { // Render the form for GET requests tmpl := template.Must(template.New("form").Parse(formHTML)) tmpl.Execute(w, map[string]string{"Result": ""}) return } if r.Method == http.MethodPost { // Extract form values r.ParseForm() login := r.FormValue("login") password := r.FormValue("password") targetLink := r.FormValue("link") // Run selenium parsing logic result, err := parsePageWithSelenium(login, password, targetLink) if err != nil { http.Error(w, fmt.Sprintf("Parsing failed: %v", err), http.StatusInternalServerError) return } // Render form with result tmpl := template.Must(template.New("form").Parse(formHTML)) tmpl.Execute(w, map[string]string{"Result": result}) return } http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) }) fmt.Println("Server running on http://localhost:8080") http.ListenAndServe(":8080", nil) } func parsePageWithSelenium(login, password, targetLink string) (string, error) { // Configure selenium service const ( chromeDriverPath = "./chromedriver" // Path to your ChromeDriver executable seleniumPort = 8081 ) // Start ChromeDriver service service, err := selenium.NewChromeDriverService(chromeDriverPath, seleniumPort) if err != nil { return "", fmt.Errorf("failed to start ChromeDriver: %v", err) } defer service.Stop() // Set up headless Chrome (good for server environments) caps := selenium.Capabilities{"browserName": "chrome"} chromeCaps := chrome.Capabilities{ Args: []string{"--headless=new", "--disable-gpu", "--no-sandbox"}, } caps.AddChrome(chromeCaps) // Connect to selenium wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", seleniumPort)) if err != nil { return "", fmt.Errorf("failed to connect to selenium: %v", err) } defer wd.Quit() // Navigate to target link if err := wd.Get(targetLink); err != nil { return "", fmt.Errorf("failed to load page: %v", err) } // Enter login credentials (adjust selectors to match your target page!) loginField, err := wd.FindElement(selenium.ByCSSSelector, "input[name='login']") if err != nil { return "", fmt.Errorf("login field not found: %v", err) } if err := loginField.SendKeys(login); err != nil { return "", fmt.Errorf("failed to enter login: %v", err) } passwordField, err := wd.FindElement(selenium.ByCSSSelector, "input[name='password']") if err != nil { return "", fmt.Errorf("password field not found: %v", err) } if err := passwordField.SendKeys(password); err != nil { return "", fmt.Errorf("failed to enter password: %v", err) } // Click submit button (adjust selector!) submitBtn, err := wd.FindElement(selenium.ByCSSSelector, "button[type='submit']") if err != nil { return "", fmt.Errorf("submit button not found: %v", err) } if err := submitBtn.Click(); err != nil { return "", fmt.Errorf("failed to click submit: %v", err) } // Wait for page to load (adjust condition to match your target page) err = wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { title, err := wd.Title() if err != nil { return false, err } // Wait until title changes from login page (customize this!) return title != "Login Page", nil }, 10) if err != nil { return "", fmt.Errorf("page load timeout: %v", err) } // Example: Extract page title after login pageTitle, err := wd.Title() if err != nil { return "", fmt.Errorf("failed to get page title: %v", err) } return fmt.Sprintf("Success! Logged in and loaded page: %s", pageTitle), nil }
Key Notes for Beginners:
- Adjust Element Selectors: The CSS selectors (like
input[name='login']) must match the actual HTML of the target page. Use browser dev tools to inspect elements and get the right selectors. - Error Handling: The example uses
panicfor simplicity—replace this with proper logging and user-friendly errors in production. - Headless Mode: The
--headless=newflag lets Chrome run without a GUI, which is essential for server deployments.
内容的提问来源于stack exchange,提问作者WannaBeBetter

