<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Elias Ruiz Diaz</title>
    <description>The latest articles on DEV Community by Elias Ruiz Diaz (@emartinrda).</description>
    <link>https://dev.to/emartinrda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4142994%2Fb05b3da2-c474-4260-a3fd-526a5d34348e.png</url>
      <title>DEV Community: Elias Ruiz Diaz</title>
      <link>https://dev.to/emartinrda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emartinrda"/>
    <language>en</language>
    <item>
      <title>Resolving an Instagram handle during an OSINT lookup, in four lines of Python</title>
      <dc:creator>Elias Ruiz Diaz</dc:creator>
      <pubDate>Fri, 25 Sep 2026 13:13:20 +0000</pubDate>
      <link>https://dev.to/emartinrda/resolving-an-instagram-handle-during-an-osint-lookup-in-four-lines-of-python-3h7e</link>
      <guid>https://dev.to/emartinrda/resolving-an-instagram-handle-during-an-osint-lookup-in-four-lines-of-python-3h7e</guid>
      <description>&lt;p&gt;A list of handles lands in my queue. Half are typos, dead accounts, or impersonations of the account I actually care about. Before I open a single browser tab I want three things: does the handle resolve, what is the numeric ID behind it, and how big is it.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The call&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;headers = {"x-access-key": "YOUR_KEY"}&lt;br&gt;
resp = requests.get(&lt;br&gt;
    "&lt;a href="https://api.hikerapi.com/v2/user/by/username" rel="noopener noreferrer"&gt;https://api.hikerapi.com/v2/user/by/username&lt;/a&gt;",&lt;br&gt;
    params={"username": "9gag"},&lt;br&gt;
    headers=headers,&lt;br&gt;
)&lt;br&gt;
print(resp.json())&lt;br&gt;
That is the whole thing. One header, one parameter, a user object back. I ran it against HikerAPI, which wraps Instagram's own endpoints behind REST.&lt;/p&gt;

&lt;p&gt;**The two fields I always pull&lt;br&gt;
**pk and follower_count.&lt;/p&gt;

&lt;p&gt;The pk matters more than it looks. Handles change, the numeric ID does not. If I record an account's pk today and tomorrow the handle is something else, I still have the same account identified. For a case file that has to survive months, that is the difference between a stable record and a string with an expiry date.&lt;/p&gt;

&lt;p&gt;follower_count is triage. A three-figure account and a seven-figure account deserve different levels of attention.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The two errors you will actually hit&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
if resp.status_code == 402:&lt;br&gt;
    raise SystemExit("balance empty")&lt;/p&gt;

&lt;p&gt;resp.raise_for_status()&lt;br&gt;
user = resp.json()&lt;br&gt;
print(user["pk"], user.get("follower_count"))&lt;br&gt;
A 402 means the prepaid balance ran out. A 429 means you are asking too fast and should wait rather than retry. Different problems, different fixes, so it is worth separating them in your first script instead of collapsing both into a bare except.&lt;/p&gt;

&lt;p&gt;Use .get() for follower_count. Private or new accounts do not always return it, and a KeyError halfway through a batch of two hundred handles is an afternoon gone.&lt;/p&gt;

&lt;p&gt;**What it costs&lt;br&gt;
**A hundred free requests to start, no card. After that it is prepaid, roughly a dollar per thousand calls, and the balance does not expire: leave the project for three months and it is still there when you come back.&lt;/p&gt;

&lt;p&gt;A two-hundred-handle investigation runs about twenty cents.&lt;/p&gt;

&lt;p&gt;**Why not scrape&lt;br&gt;
**I measured this recently from a residential IP, not a server: instagram.com no longer renders profile data for logged-out visitors, so the HTML arrives heavy and empty and there is nothing to parse.&lt;/p&gt;

&lt;p&gt;Four lines plus honest error handling beats maintaining a scraper that breaks every time they ship a front-end change.&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
