Bing

Bing

Today, Satya Nadella was sitting behind his giant mahogany desk when he noticed an anomoly. “Wait a minute. This guy is cheating! Let’s get him! Our stockholders depend on it!” Shortly after, my accounts got Bing Bonged straight onto the time out bench. Let’s see if we could do something about this…

Bing

Well, crap. I typically use a VPN for reasons, and assumed that was why I was flagged. Turns out they figured out I was bot-ersizing searches. Naughty me. I’ve learned my lesson and will promise to do better.

With that obvious fib aside, let’s add in some randomized user agents for desktop and mobile. Users typically have a bit more randomization going on in their lives. Sometimes they’ll do some searches, go to the bathroom, use a different computer, eat lunch, use a different browser, search for porn, and quickly hide the browser from family members that don’t understand what privacy means.

def get_random_user_agent(isMobile=False):
    desktop_user_agents = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15",
    ]

    mobile_user_agents = [
        "Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36",
        "Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/605.1.15",
        "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; Nexus 5 Build/KOT49H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
    ]

    if isMobile:
        return random.choice(mobile_user_agents)
    else:
        return random.choice(desktop_user_agents)

While we’re at it, why not set some helpful browser arguments and some random resolutions. Using a browser without a resolution would be a giant red flag for the server on the other end. Let’s not make their machines worry that we’re trying anything nefarious.

context_args = {
    'viewport': {'width': random.choice([1366, 1440, 1536, 1920]), 'height': random.choice([768, 900, 1024, 1080])},
    'user_agent': get_random_user_agent(isMobile),
    'java_script_enabled': True,
    'bypass_csp': True
}
try:
    browser = playwright.firefox.launch(headless=HEADLESS)
    context = browser.new_context(**context_args)

    context.add_init_script('''() => {
        Object.defineProperty(navigator, 'webdriver', { get: () => false });
        window.navigator.chrome = { runtime: {} };
        Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
        Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });
    }''')

    page = context.new_page()
    page.wait_for_timeout(random.uniform(3000, 7000))

Let’s add in a realistic delay function. Humans don’t usually act so robotic. Typing is hard. Navigating with the mouse takes time and dexterity. Let’s add some blood and guts into our searching curiosity. Combined with our random Wikipedia article search, we’re now more human than human.

def human_typing(page, selector, text, typo_probability=0.008):
    def make_typo(char):
        typos = {
            'insert': lambda c: c + random.choice('abcdefghijklmnopqrstuvwxyz'),
            'delete': lambda c: '',
            'replace': lambda c: random.choice('abcdefghijklmnopqrstuvwxyz')
        }
        typo_type = random.choice(['insert', 'delete', 'replace'])
        return typos[typo_type](char)

    page.click(selector)  # Ensure the search box is focused

    for char in text:
        if random.random() < typo_probability:
            char = make_typo(char)

        page.type(selector, char)
        sleep(random.uniform(0.1, 0.5))

There we go! We should be all set now. Let’s see if there are any errors…

Bing

Awesome! Thank you Mr. Bot. You’re the best! Now to set it and forget it. I’ll standby for my “job’s done” Slack notification to make sure everything goes well the next few days.

Naturally, I don’t give two craps about the rewards. This is purely entertainment value with trying to avoid getting flagged. Maybe we should think about not completing 100% of the rewards all the time. That may put me on an internal list, huh?

On an unrelated note, I’ve added my Twitter account on the left if you wanna chat. I’d rather not add a comment section with embedded, privacy ignoring Javascript. I care about y’alls well-being. ❤️