Quay lại blog

Xuất JSON Tìm kiếm Google ra CSV để Phân tích

Michael Lee
Michael Lee

Expert Network Defense Engineer

15-Sep-2026

TL;DR:

  • Một tệp CSV kết quả tìm kiếm của Google cần có ngữ cảnh truy vấn bên cạnh các hàng của nó. Giữ lại thời gian yêu cầu và quan sát để mỗi kết quả vẫn có thể được hiểu sau khi xuất khẩu.
  • CSV là một phiên bản của JSON. Giữ lại dữ liệu thô, phân biệt giá trị vắng mặt và giá trị null, và ghi lại ý nghĩa của các ô đã biến đổi.
  • Một tệp chỉ có tiêu đề cần có bản ghi hoạt động. Các bản ghi đang chờ xử lý, thất bại, không ánh xạ và tồn tại nhưng trống đều có thể tạo ra không có hàng thực thể vì lý do khác nhau.

Một bảng tính có thể giữ lại mọi tiêu đề và vẫn mất đi ý nghĩa của tìm kiếm đã sinh ra nó. Nếu không có truy vấn, ngữ cảnh đã gửi và thời gian quan sát, một hàng trở nên khó so sánh hoặc truy xét. Một ô trống tạo ra một sự mơ hồ khác: giá trị đó có bị thiếu, null, hay bị từ chối bởi phép biến đổi?

API Tìm kiếm Google không Scrapeless cung cấp dữ liệu tìm kiếm có cấu trúc ở phía đầu. Hướng dẫn này xây dựng một tệp CSV kết quả tìm kiếm Google từ một bản ghi đã lưu bằng cách sử dụng một trình xuất Python cục bộ. Việc tạo CSV, xử lý bảng tính và lưu trữ tệp là chức năng của chương trình ví dụ, không phải là tuyên bố rằng API trả về định dạng xuất khẩu này trực tiếp.

Các yêu cầu trước và Bao bì Captures

Trình xuất cần Python và một bản ghi JSON đã lưu với request, http_status, và response. Bao gồm run_id, requested_at, và received_at khi người thu thập ghi lại chúng. Những trường bên ngoài này thuộc về ứng dụng thu thập, không phải là bao bọc phản hồi gốc của API.

Quy trình yêu cầu tìm kiếm Google phân biệt dữ liệu tác vụ HTTP 200 với công việc đang chờ HTTP 201. Giữ lại kết quả HTTP với phản hồi trước khi làm phẳng bất kỳ điều gì. Đọc một trường hữu cơ vắng mặt từ phản hồi đang chờ và thay thế bằng danh sách trống sẽ xóa bỏ sự phân biệt đó.

Không cần khóa API hay gói bên thứ ba cho phép biến đổi cục bộ. Việc tạo ra một bản ghi tài khoản là một bước xác thực riêng biệt, điều này không được thực hiện trong bài viết này. Các kiểm tra cục bộ sử dụng các bản ghi tổng hợp để kiểm tra các kiểu dữ liệu, trạng thái trống, Unicode, và văn bản nhạy cảm với bảng tính.

Mô hình giá trị JSON giữ lại các mảng, đối tượng, null và chuỗi không ánh xạ trực tiếp tới các ô phẳng. Giữ nguyên bản ghi gốc sau khi xuất để các nhà phân tích sau này có thể khôi phục các mô-đun bị bỏ qua và các giá trị gốc chính xác.

Quyết định Cột Nào Mang Ngữ Cảnh và Ý Nghĩa

Lặp lại định danh chạy, thời gian yêu cầu và nhận, truy vấn chính xác khi có sẵn, và yêu cầu được phân phối trên mỗi hàng kết quả. Yêu cầu đầy đủ giữ lại các cài đặt vượt ra ngoài các cột tiện lợi cố định và khiến việc xuất khẩu dễ kiểm toán hơn.

Các tham số tìm kiếm Google bao gồm cài đặt quốc gia và ngôn ngữ, nhưng chế độ URL đầy đủ có thể mang cấu hình bên trong url. Do đó, một cột q trống không nhất thiết cho thấy một truy vấn đã gửi bị thiếu. Kiểm tra request_json; không nên tái cấu trúc một truy vấn hiệu quả bằng cách đoán từ một trường tiện lợi trống.

Thứ tự mảng hữu cơ và vị trí trả về là các cột riêng biệt. ordinal ghi lại thứ tự nguồn dựa trên zero của mục. position chỉ được giữ lại khi nó là một số nguyên dương, với các giá trị boolean bị từ chối một cách rõ ràng. Trình xuất không chế tạo xếp hạng từ thứ tự mảng.

Các trường văn bản và vị trí mỗi trường có một cột trạng thái đi kèm. missing, null, và value giải thích các trường hợp chung. invalid đánh dấu một vị trí không sử dụng được; unexpected_type đánh dấu một giá trị trường văn bản không phải chuỗi được giữ lại dưới dạng JSON đã tuần tự hóa thay vì im lặng bị loại bỏ.

Phân tách Trích dẫn CSV Từ Sự Diễn Giải Bảng Tính

Một người viết CSV xử lý các dấu phân cách và văn bản được trích dẫn; nó không quyết định cách mà một bảng tính đánh giá một ô. Sử dụng người viết CSV của Python cho các dấu phẩy, dấu ngoặc kép và ngắt dòng nhúng thay vì ghép các chuỗi thủ công.

Chương trình mở đầu ra của nó với newline=""utf-8-sig. Cài đặt đầu tiên cho phép mô-đun CSV quản lý ranh giới bản ghi. Chữ ký UTF-8 có thể giúp một bảng tính nhận biết văn bản có dấu hoặc không phải Latin, nhưng hành vi nhập của ứng dụng đích vẫn cần được kiểm tra.
Một giá trị bắt đầu bằng ký tự công thức có thể được hiểu như một biểu thức khi mở trong bảng tính. Hướng dẫn tấn công CSV mô tả lý do tại sao CSV đúng ngữ pháp không đủ để làm cho văn bản không đáng tin cậy trở nên vô hại.

Trình xuất này thêm một dấu nháy đơn cho các ký tự có công thức dẫn đầu đã chọn, bao gồm các biến thể toàn chiều và cho các tab hoặc ngắt dòng dẫn đầu. Nó áp dụng chính sách cho ngữ cảnh yêu cầu cũng như văn bản kết quả. Các vị trí số sử dụng một quy tắc xác thực riêng biệt.

Bắt đầu Scraping với Scrapeless

Tăng cường quy trình tự động hóa và scraping web của bạn với Scrapeless!
Đăng ký hôm nay và nhận 5 đô la tín dụng miễn phíkhông cần thẻ tín dụng.

Nhận ngay tín dụng miễn phí của bạn trong Bảng điều khiển Scrapeless.

Chạy Trình Xuất JSON-to-CSV Địa Phương

Lưu chương trình dưới dạng serp_csv.py, sau đó chạy python3 serp_csv.py capture.json organic.csv. Nó đọc dữ liệu và ghi organic.csv cùng với organic.csv.run.json đi kèm. Các tệp đầu ra hiện có sẽ bị thay thế; hãy chọn một thư mục xuất chuyên dụng hoặc tên duy nhất khi giữ lại nhiều phiên bản.

Chương trình từ chối các đường dẫn đầu ra sẽ ghi đè lên capture đầu vào. Nó không thay đổi JSON gốc, không gửi yêu cầu API hay lấy các tác vụ đang chờ xử lý.

python Copy
import argparse
import csv
import json
from pathlib import Path

FIELDS = ["run_id", "requested_at", "received_at", "q", "request_json", "ordinal",
          "position", "position_state", "title", "title_state", "link", "link_state",
          "snippet", "snippet_state"]

def spreadsheet_text(value):
    text = "" if value is None else str(value)
    stripped = text.lstrip()
    if (stripped.startswith(("=", "+", "-", "@", "=", "+", "-", "@"))
            or text.startswith(("\t", "\r", "\n"))):
        return "'" + text
    return text

def field(row, name):
    if name not in row:
        return "", "missing"
    value = row[name]
    if value is None:
        return "", "null"
    if name == "position":
        return (value, "value") if type(value) is int and value > 0 else ("", "invalid")
    if isinstance(value, str):
        return spreadsheet_text(value), "value"
    return spreadsheet_text(json.dumps(value, ensure_ascii=False)), "unexpected_type"

def export(source, target):
    source, target = Path(source), Path(target)
    sidecar = target.with_suffix(target.suffix + ".run.json")
    if source.resolve() in (target.resolve(), sidecar.resolve()):
        raise ValueError("Output paths must differ from input")
    record = json.loads(source.read_text(encoding="utf-8"))
    request = record.get("request")
    if not isinstance(request, dict) or not isinstance(request.get("input"), dict):
        raise ValueError("Expected a capture record with request.input")
    payload = record.get("response")
    rows = payload.get("organic_results") if isinstance(payload, dict) else None
    status = record.get("http_status")
    if status == 201:
        state, rows = "pending", []
    elif status != 200:
        state, rows = ("transport_error" if status is None else "http_error"), []
    elif not isinstance(rows, list) or any(not isinstance(x, dict) for x in rows):
        state, rows = "unmapped", []
    else:
        state = "observed" if rows else "empty"
    context = {
        "run_id": spreadsheet_text(record.get("run_id")),
        "requested_at": spreadsheet_text(record.get("requested_at")),
        "received_at": spreadsheet_text(record.get("received_at")),
        "q": spreadsheet_text(request["input"].get("q")),
        "request_json": spreadsheet_text(json.dumps(request, ensure_ascii=False, sort_keys=True)),
    }
    with target.open("w", encoding="utf-8-sig", newline="") as handle:
        writer = csv.DictWriter(handle, fieldnames=FIELDS)
        writer.writeheader()
        for ordinal, item in enumerate(rows):
            output = dict(context, ordinal=ordinal)
            for name in ("position", "title", "link", "snippet"):
                output[name], output[name + "_state"] = field(item, name)
            writer.writerow(output)
    sidecar.write_text(json.dumps({"source": str(source), "run_id": record.get("run_id"),
        "state": state, "rows": len(rows), "request": request,
        "requested_at": record.get("requested_at"), "received_at": record.get("received_at"),
        "export_policy": "spreadsheet_text_prefix_v1; original values remain in source JSON"},
        ensure_ascii=False, indent=2), encoding="utf-8")
    print(f"Exported {len(rows)} organic rows; state={state}; metadata={sidecar}")
    return state, len(rows)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("source")
    parser.add_argument("target")
    args = parser.parse_args()
    export(args.source, args.target)

Sidecar ghi lại trạng thái bộ sưu tập, số lượng hàng dự kiến, đường dẫn nguồn, yêu cầu, thời gian, và chính sách xuất. Một CSV chỉ chứa tiêu đề vẫn có thể giải thích miễn là bản ghi đó tồn tại cùng với nó. Giữ cả hai tệp đầu ra cùng nhau khi chuyển giao xuất cho người khác.

Kiểm Tra Null và Dữ Liệu Tổ Chức Không Đúng

Một mảng tổ chức rỗng hiện có sẽ tạo state=empty. HTTP 201 sẽ tạo pending, một trạng thái HTTP bị thiếu sẽ trở thành transport_error, và một trạng thái không phải 200 sẽ trở thành http_error trong mô hình trạng thái của ứng dụng này. Những kết quả này có thể chia sẻ một số lượng hàng bằng không mà không chia sẻ một ý nghĩa.

Nếu trường tổ chức không có, không phải là một mảng, hoặc chứa một mục không phải là đối tượng, toàn bộ sự chiếu trở thành unmapped. Chương trình không xuất hàng tổ chức cho lần chạy đó. Điều này tránh việc lặng lẽ bỏ qua các mục không đúng định dạng trong khi mô tả các hàng còn lại như một sự chiếu hoàn chỉnh.

Các trường tùy chọn được xử lý chặt chẽ hơn. Một đoạn mã bị thiếu để lại một ô trống và một trạng thái trường rõ ràng mà không từ chối mục tổ chức. Một giá trị phức tạp không mong đợi vẫn được biểu diễn dưới dạng văn bản JSON, vì vậy giá trị bất thường có thể vẫn được xem xét.

Đây là các chính sách của ứng dụng. Tài liệu chúng bên cạnh xuất và xem xét lại một cách có chủ đích nếu người tiêu dùng cần một lược đồ khác. Một cột trạng thái trường hữu ích chính xác bởi vì một nhà phân tích khác không nên phải suy diễn sự biến đổi từ một vài ô nhìn thấy được.

Xác Minh Chuyển Giao Bảng Tính

Đọc đầu ra bằng một trình phân tích CSV và so sánh các bản ghi logic, không phải các dòng vật lý. Một đoạn mã được trích dẫn có thể chứa một dòng mới mà không tạo ra một kết quả tìm kiếm mới. Xác nhận rằng số lượng sidecar khớp với các hàng được phân tích và mỗi hàng đều mang ngữ cảnh yêu cầu của nó.

Kiểm tra các giá trị nhạy cảm với Unicode và công thức trong ứng dụng mà nhóm thực sự sử dụng. Chính sách dấu nháy đơn cố ý thay đổi đại diện xuất và có thể hiện rõ trong một số trình xem. Nó không phải là một đảm bảo phổ quát trên tất cả các cài đặt nhập khẩu và ứng dụng bảng tính.

Bao gồm hành vi lưu và mở lại trong bài kiểm tra. Cuộc thảo luận về nhập khẩu bảng tính minh họa lý do tại sao việc xử lý thoát lại xứng đáng được xem xét cụ thể cho ứng dụng. Nhập các cột liên quan dưới dạng văn bản và sử dụng JSON gốc bất cứ khi nào các chuỗi nguồn chính xác là cần thiết.

Một chuyến đi địa phương thành công xác nhận tính nhất quán của sự chiếu này. Nó không thiết lập rằng mẫu tìm kiếm thượng nguồn là đầy đủ, đại diện, hoặc phù hợp cho một kết luận xếp hạng mà không có phân tích thêm.

Kết Luận

Xuất ngữ cảnh yêu cầu cùng với các kết quả, giữ trạng thái trường nơi mà khoảng trống sẽ che giấu ý nghĩa, và giữ JSON thô. Một CSV cộng với một bản ghi chạy cung cấp cho nhà phân tích tiếp theo đủ thông tin để phân biệt một phần rỗng đo được từ bộ sưu tập không khả dụng.

Một quy trình nghiên cứu nội dung SERP có thể sử dụng các quan sát xuất để xây dựng danh sách đọc có thể xem lại trước khi soạn thảo một tóm tắt nội dung.

Xây Dựng Quan Sát Tìm Kiếm Tiếp Theo Của Bạn

Sử dụng API Tìm kiếm Google Không Phân Tích để lấy dữ liệu tìm kiếm trong quy trình này. Xem xét giá cả của Scrapeless khi lên kế hoạch thu thập, và giữ cho các tham số Tìm kiếm Google bên cạnh cấu hình của bạn.

Thảo luận về việc triển khai của bạn với cộng đồng trên Discord hoặc Telegram.

Câu Hỏi Thường Gặp

H: API Tìm kiếm Google có trực tiếp tạo ra CSV này không?

Không. Trình xuất được minh họa biến đổi JSON đã lưu cục bộ. Việc tạo tệp và sơ đồ bên cạnh thuộc về chương trình Python.

H: Tại sao phải giữ request_json khi truy vấn đã có một cột?

Yêu cầu đầy đủ giữ lại các cài đặt tùy chọn và đầu vào URL đầy đủ mà chỉ một cột truy vấn không thể đại diện.

H: Có phải dấu ngoặc kép trong CSV ngăn cản việc diễn giải công thức không?

Không. Xử lý dấu phân cách và đánh giá bảng tính là tách biệt. Áp dụng một chính sách văn bản đã được tài liệu hóa và xác minh quy trình nhập dự kiến.

H: Có phải một CSV trống có nghĩa là tìm kiếm không trả về kết quả nào không?

Không nhất thiết. Kiểm tra trạng thái sơ đồ bên để phân biệt một mảng rỗng hiện có từ bộ sưu tập đang chờ, thất bại, hoặc chưa được lập bản đồ.

H: Liệu các giá trị gốc có thể được phục hồi không?

Có, từ việc giữ lại bản ghi đầu vào. CSV là một dự đoán và cố ý biến đổi một số biểu diễn văn bản cho việc sử dụng bảng tính.

Tại Scrapless, chúng tôi chỉ truy cập dữ liệu có sẵn công khai trong khi tuân thủ nghiêm ngặt các luật, quy định và chính sách bảo mật trang web hiện hành. Nội dung trong blog này chỉ nhằm mục đích trình diễn và không liên quan đến bất kỳ hoạt động bất hợp pháp hoặc vi phạm nào. Chúng tôi không đảm bảo và từ chối mọi trách nhiệm đối với việc sử dụng thông tin từ blog này hoặc các liên kết của bên thứ ba. Trước khi tham gia vào bất kỳ hoạt động cạo nào, hãy tham khảo ý kiến ​​cố vấn pháp lý của bạn và xem xét các điều khoản dịch vụ của trang web mục tiêu hoặc có được các quyền cần thiết.

Bài viết phổ biến nhất

Danh mục