You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#开发Google查重工具遇429错误:如何绕过或获取重试时间?

Fixing 429 Too Many Requests Error in Your C# Google Search Tool

Hey there, let's work through this 429 error you're facing with your plagiarism checker. The issue boils down to Google's anti-scraping protections—your current requests look too "bot-like," and you're hitting rate limits without handling them properly. Let's break down the fixes step by step:

1. Fix Your Request Headers (Critical!)

Your code tries to set a User-Agent but does it incorrectly. Google flags requests without a proper browser-like User-Agent immediately. Instead of adding it to Headers, set the UserAgent property directly, and add other common headers to mimic a real browser:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(SearchResults);
// Mimic a real Chrome browser on Windows
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
request.Referer = "https://www.google.com/";

2. Extract Retry-After Time from 429 Responses

When Google sends a 429 error, it usually includes a Retry-After header that tells you how many seconds to wait before retrying. You need to catch the specific WebException (not a generic Exception) to access this header:

catch (WebException ex)
{
    if (ex.Response is HttpWebResponse response && response.StatusCode == HttpStatusCode.TooManyRequests)
    {
        string retryAfter = response.Headers["Retry-After"];
        if (int.TryParse(retryAfter, out int secondsToWait))
        {
            MessageBox.Show($"Rate limited! Please wait {secondsToWait} seconds before trying again.", "Too Many Requests", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            // You can automatically retry here using Thread.Sleep (sync) or Task.Delay (async)
            // Thread.Sleep(secondsToWait * 1000);
            // SearchAndWrite(text); // Retry the request
        }
        else
        {
            MessageBox.Show("Rate limited, but no retry time provided. Wait a few minutes and try again.", "Too Many Requests", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
    else
    {
        MessageBox.Show(ex.ToString(), "An error has occurred!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
    }
}

3. Implement a Rate Limiting/Retry Strategy

To avoid hitting 429 in the first place, add a delay between requests. If you do hit the limit, use an exponential backoff strategy (wait longer each time you get an error) instead of fixed delays:

private int retryAttempts = 0;
private void SearchAndWrite(string text)
{
    try
    {
        // ... your existing request and parsing code ...
        // Reset retry attempts on successful request
        retryAttempts = 0;
    }
    catch (WebException ex)
    {
        if (ex.Response is HttpWebResponse response && response.StatusCode == HttpStatusCode.TooManyRequests)
        {
            retryAttempts++;
            // Exponential backoff: wait 2^retryAttempts seconds
            int waitTime = (int)Math.Pow(2, retryAttempts);
            MessageBox.Show($"Rate limited! Retrying in {waitTime} seconds...", "Too Many Requests", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            Thread.Sleep(waitTime * 1000);
            // Retry the request
            SearchAndWrite(text);
        }
        else
        {
            MessageBox.Show(ex.ToString(), "An error has occurred!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            retryAttempts = 0;
        }
    }
}

4. Switch to HttpClient (Modern Alternative)

HttpWebRequest is outdated—HttpClient is better for managing connections, headers, and async operations. Here's a quick rewrite of your search logic using HttpClient:

private static readonly HttpClient _httpClient = new HttpClient();

// Initialize headers once in your form constructor
public YourFormName()
{
    InitializeComponent();
    // Set default headers to mimic a real browser
    _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36");
    _httpClient.DefaultRequestHeaders.Accept.ParseAdd("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
    _httpClient.DefaultRequestHeaders.Referrer = new Uri("https://www.google.com/");
}

private async void SearchAndWrite(string text)
{
    listBox1.Items.Clear();
    // Properly escape the search query to handle special characters
    string searchUrl = $"http://google.com/search?q={Uri.EscapeDataString(text.Trim())}";
    try
    {
        HttpResponseMessage response = await _httpClient.GetAsync(searchUrl);
        response.EnsureSuccessStatusCode(); // Throws HttpRequestException on 4xx/5xx errors
        string htmlContent = await response.Content.ReadAsStringAsync();
        
        // Your HtmlAgilityPack parsing logic
        HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument();
        html.LoadHtml(htmlContent);
        // Handle null case if no links are found
        foreach (HtmlNode link in html.DocumentNode.SelectNodes("//a[@href]") ?? Enumerable.Empty<HtmlNode>())
        {
            string hrefValue = link.GetAttributeValue("href", string.Empty);
            if (!hrefValue.ToUpper().Contains("GOOGLE") && hrefValue.Contains("/url?q=") && hrefValue.ToUpper().Contains("HTTP://"))
            {
                int index = hrefValue.IndexOf("&");
                if (index > 0)
                {
                    hrefValue = hrefValue.Substring(0, index);
                    listBox1.Items.Add(hrefValue.Replace("/url?q=", ""));
                }
            }
        }
    }
    catch (HttpRequestException ex)
    {
        if (ex.StatusCode == HttpStatusCode.TooManyRequests)
        {
            double? secondsToWait = ex.Response.Headers.RetryAfter?.Delta?.TotalSeconds;
            if (secondsToWait.HasValue)
            {
                MessageBox.Show($"Rate limited! Wait {secondsToWait.Value:N0} seconds before retrying.", "Too Many Requests", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                await Task.Delay(TimeSpan.FromSeconds(secondsToWait.Value));
                await SearchAndWrite(text);
            }
            else
            {
                MessageBox.Show("Rate limited. Wait a few minutes and try again.", "Too Many Requests", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
        else
        {
            MessageBox.Show(ex.ToString(), "An error has occurred!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }
    }
}

Key Notes

  • Always use Uri.EscapeDataString() for your search query—your current code doesn't handle special characters (like spaces or ampersands) which can break the URL.
  • Google's terms of service restrict scraping their search results. Make sure your tool complies with their policies to avoid getting your IP blocked long-term.

内容的提问来源于stack exchange,提问作者kahveciderin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 13:12:45