塔吉特半价邮编查找

窥见隔壁塔吉特邮编大法半价购买培根果汁等等的神秘交易,以半价购得无数水果生鲜。然而,总需等待他人的邮编,遂写下一个隐秘脚本,遍历所有商店,查询最终价格。为免重复劳动,我将所有塔吉特商店的信息存入store_data.csv文件,此处共享。运行神秘程序target.py,输入欲购买商品的TCIN编号(即塔吉特商品网址中A-后的数字串),程序即会遍历所有商店价格,输出打折的store_id。所有商店价格亦可保存至对应csv文件中,手动根据store_id在store_data.csv中查询店铺位置与邮编即可。

store_data.csv

target.py 1.0
import requests
import pandas as pd
import time
import random
from tqdm import tqdm
import socks
import socket
import threading
import csv

USING_PROXY = True
TRYING_TIMES = 5

# Function to fetch and parse the latest SOCKS5 proxy list
def fetch_proxies():
    url = "https://raw.githubusercontent.com/proxifly/free-proxy-list/main/proxies/protocols/socks5/data.txt"
    response = requests.get(url)
    if response.status_code == 200:
        proxies = response.text.splitlines()
        # Validate and clean proxy list
        valid_proxies = [proxy.strip() for proxy in proxies if proxy.startswith("socks5://")]
        return valid_proxies
    else:
        print(f"Failed to download proxy list with status code: {response.status_code}")
        return []

# Function to periodically update the proxy list
def update_proxies():
    global proxies_list
    while True:
        print("Updating proxy list...")
        proxies_list = fetch_proxies()
        print(f"Updated proxy list with {len(proxies_list)} proxies.")
        time.sleep(300)  # Update every 5 minutes

if USING_PROXY:
    # Initialize proxy list
    proxies_list = fetch_proxies()
    
    # Start a background thread to update the proxy list periodically
    proxy_thread = threading.Thread(target=update_proxies, daemon=True)
    proxy_thread.start()

# Function to generate random headers
def generate_random_headers():
    user_agent_templates = [
        "Mozilla/5.0 (Windows NT {win_ver}; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{chrome_ver} Safari/537.36",
        "Mozilla/5.0 (Windows NT {win_ver}; Win64; x64; rv:{firefox_ver}) Gecko/20100101 Firefox/{firefox_ver}",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X {mac_ver}) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/{safari_ver} Safari/605.1.15",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{chrome_ver} Safari/537.36",
        "Mozilla/5.0 (Windows NT {win_ver}; WOW64; rv:{firefox_ver}) Gecko/20100101 Firefox/{firefox_ver}"
    ]
    accept_language_options = [
        "en-US,en;q=0.9",
        "en-GB,en;q=0.9",
        "en-CA,en;q=0.9",
        "en-AU,en;q=0.9",
        "fr-FR,fr;q=0.9,en;q=0.8"
    ]
    accept_encoding_options = [
        "gzip, deflate, br",
        "gzip, deflate",
        "br"
    ]

    template = random.choice(user_agent_templates)
    win_ver = f"{random.randint(6, 10)}.{random.randint(0, 1)}"
    chrome_ver = f"{random.randint(70, 90)}.0.{random.randint(3000, 4000)}.{random.randint(100, 150)}"
    firefox_ver = f"{random.randint(60, 89)}.0"
    mac_ver = f"10_{random.randint(10, 15)}_{random.randint(1, 6)}"
    safari_ver = f"{random.randint(10, 14)}.{random.randint(0, 1)}.{random.randint(1, 3)}"
    
    user_agent = template.format(win_ver=win_ver, chrome_ver=chrome_ver, firefox_ver=firefox_ver, mac_ver=mac_ver, safari_ver=safari_ver)
    accept_language = random.choice(accept_language_options)
    accept_encoding = random.choice(accept_encoding_options)
    
    headers = {
        "User-Agent": user_agent,
        "Accept": "application/json, text/plain, */*",
        "Accept-Encoding": accept_encoding,
        "Accept-Language": accept_language,
        "Connection": "keep-alive"
    }
    return headers

def set_proxy(proxy):
    proxy_parts = proxy.replace("socks5://", "").split(":")
    socks.set_default_proxy(socks.SOCKS5, proxy_parts[0], int(proxy_parts[1]))
    socket.socket = socks.socksocket

def reset_proxy():
    socks.set_default_proxy(None)
    socket.socket = socket.socket

def remove_invalid_proxy(proxy):
    global proxies_list
    proxies_list = [p for p in proxies_list if p != proxy]

def fetch_data():
    # 提示用户输入 tcin
    print("提示: 14911563: T Bone, 54273119: Ribeye, 54640786: New York Strip")
    tcin = input("请输入 tcin: ")

    # 目标URL的基础部分
    url_base = "https://redsky.target.com/redsky_aggregations/v1/web/pdp_client_v1?key=9f36aeafbe60771e321a7cc95a78140772ab3e96&tcin={tcin}&is_bot=false&store_id={store_id}&pricing_store_id={pricing_store_id}&has_pricing_store_id=true"

    # Read existing store IDs
    try:
        store_data = pd.read_csv("store_data.csv")
        store_ids = store_data['store_id'].tolist()
        postal_codes = store_data['postal_code'].tolist()
        location_names = store_data['location_name'].tolist()
    except FileNotFoundError:
        print("Store data CSV file not found.")
        return

    # 创建一个CSV文件来存储结果
    filename = f"price_data_tcin_{tcin}.csv"
    with open(filename, mode='w', newline='', encoding='utf-8') as file:
        writer = csv.writer(file)
        # 写入表头
        writer.writerow(["store_id", "location_name", "postal_code", "current_retail", "formatted_current_price", "reg_retail"])
        
        if USING_PROXY:
            proxy = random.choice(proxies_list)
            set_proxy(proxy)

        # 遍历 store_id
        for store_id, postal_code, location_name in tqdm(zip(store_ids, postal_codes, location_names), desc=f"Fetching price data for tcin {tcin}", unit="request", total=len(store_ids)):
            headers = generate_random_headers()

            for _ in range(TRYING_TIMES):
                # 格式化URL
                url = url_base.format(tcin=tcin, store_id=store_id, pricing_store_id=store_id)
                
                # 发送GET请求
                try:
                    response = requests.get(url, headers=headers, timeout=10)
                    # 确认请求成功
                    if response.status_code == 200:
                        # 解析JSON响应
                        data = response.json()
                        # 获取"price"字段
                        price_info = data.get("data", {}).get("product", {}).get("price", {})
                        # 提取需要的信息
                        current_retail = price_info.get("current_retail")
                        formatted_current_price = price_info.get("formatted_current_price")
                        reg_retail = price_info.get("reg_retail")

                        # 写入CSV文件
                        writer.writerow([store_id, location_name, postal_code, current_retail, formatted_current_price, reg_retail])
                        if "formatted_current_price_type" in price_info and price_info["formatted_current_price_type"] != "reg":
                            # 更新进度条后缀信息
                            tqdm.write(f"Store ID: {store_id}, Location Name: {location_name}, Postal Code: {postal_code}, Current Price: {formatted_current_price}")
                        break
                    elif response.status_code == 404:
                        # 换一个User-Agent
                        if USING_PROXY:
                            remove_invalid_proxy(proxy)
                            proxy = random.choice(proxies_list)
                            set_proxy(proxy)
                            headers = generate_random_headers()
                        print(f"Received 404 for store_id {store_id}, changing Proxy and User-Agent.")
                    else:
                        print(f"Request failed for store_id {store_id} with status code: {response.status_code}")
                        break
                except requests.exceptions.RequestException as e:
                    print(f"Request exception for store_id {store_id}: {e}")
                    if USING_PROXY:
                        remove_invalid_proxy(proxy)
                        proxy = random.choice(proxies_list)
                        set_proxy(proxy)
                        headers = generate_random_headers()
                    else:
                        break

                # 避免发送请求过快,加入随机延迟
                # time.sleep(random.uniform(0.5, 1.5))

            reset_proxy()

    print(f"数据已成功保存到 {filename} 文件中")

# Run the main function
fetch_data()

Update:提示:用多了,可能会被Target封IP,可能过两天就好了。或者修改 USING_PROXY = True (不确保代理是否有效)

Update:版本0.2: 为了避免封ip, 默认启用代理 USING_PROXY = True (可以自行关闭False,提升速度,风险自理),设置 TRYING_TIMES = 5 (每个store_id最大尝试5次)。

Update:

Update:版本1.0:

以及 target 店铺位置名称

92 个赞

感谢lz简单粗暴的喂饭

太6了zszs

来人啊,给楼主加个“Target 救世主” 的徽章

13 个赞

来人啊,赐钛金勋章

8 个赞

跪了…
但…我還是不會用:melting_face::melting_face::melting_face::melting_face:

先点赞。我也不会用。

不知道靶子店什么时候修复bug

吃不到葡萄说葡萄是酸的?

冲太了,恭喜楼主

钛厉害啦!

钛棒了 :+1:

我看到了我看到了 :smiling_face_with_three_hearts: :smiling_face_with_three_hearts:
你赶紧删了 你赶紧删了 :sob: :sob: :sob: :sob: :sob:

看一下代码,直接运行py文件然后会创造出这个csv文件

赞,就差一个人把这个弄成 gpt agent了 :yaoming: :yaoming:

? 这有啥吃不到的 :sweat_smile:

来人升钛 移入白金宫 :smiling_face_with_three_hearts:

bug有了,现在就差个stay at home wife帮我购物啦,不知道在哪可以领

1 个赞

啥, stay at home wife竟然还会用bug :yaoming:

赶紧挪到白金lounge去。。

顺便给楼主加个钛金吧

1 个赞