
If you’ve ever built a scraper for your app, you know the painful part isn’t downloading the page. It’s turning that messy HTML into clean, structured data. You end up writing regex, CSS selectors, beautiful soup logic, and then a few weeks later the website changes and everything breaks. That’s the cycle. Today we’re going to break it by building something a little different: a universal AI data pipeline. Instead of custom parsers for every website, we’ll take raw HTML from a real page, send it through Ernie 5.1, and get back database-ready JSON we can immediately use inside an application.
Why Traditional Scraping Gets Exhausting So Fast
The first scrape always feels fine. You inspect the page, pick out the CSS classes, write a few loops, clean up the text, and maybe handle a missing field or two. It works. Then you need to scrape a second site. The layout is completely different. The data you care about is buried in a
Then a third site. Then the first site redesigns their job listings page. Your extraction rules that matched .job-title > strong now return nothing. Suddenly you’re spending more time maintaining parsers than building the thing you actually wanted to build. That’s the real cost. Not the initial coding, but the never-ending maintenance of fragile rules that break at the worst possible moment. This isn’t a new problem. It’s just that most solutions are still stuck in the same pattern: writing site-specific logic to transform unstructured HTML into structured fields.
The Idea Behind a Universal AI Data Pipeline
What if you could hand a block of raw HTML to a model and say, “Here’s the schema I want. Give me back only the data, structured exactly like this”? That’s the shift. You stop thinking about how to dig the information out of a particular DOM tree and start defining the output you need. The model handles the mess.
This works because large language models are surprisingly good at identifying and extracting structured information from noisy text. You don’t have to pre-clean the HTML, strip scripts, or even remove duplicated content. You can throw the whole tangled block in, describe what matters, and get clean JSON on the other side.
In this case I’m using Ernie 5.1 for the pipeline. The reason isn’t just performance. It’s because this kind of workflow can get expensive incredibly fast. When you’re sending thousands of tokens of raw HTML to a language model, API costs actually matter, especially if you’re building a SaaS or processing data at scale. Ernie 5.1 is designed around large-scale text workflows like data extraction and structuring. So throughout this project, we’ll see how it handles a real engineering task.
Setting Up the Pipeline with Python and the OpenAI SDK
Even though Ernie 5.1 comes from Baidu, you don’t need to learn a brand new SDK. It’s compatible with the standard OpenAI Python library. That alone removes a huge amount of friction. I’ll start by installing the openai package, then create a fresh Python file. The setup should look extremely familiar.
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://qianfan.baidubce.com/v2"
)
The only thing you’re really changing is that base_url. It points to Baidu’s Qianfan endpoint instead of OpenAI’s. Everything else: the chat completions call, message formatting, temperature, all of it works exactly the same way. If you’ve already built applications with the OpenAI SDK, you’ll feel right at home.
Before we send anything to the model, let’s look at the kind of data we’re going to parse. I’m not feeding it tidy, pre-cleaned content. I have a messy block of HTML copied directly from a public webpage. It’s full of nested tags, random attributes, duplicated text, and a lot of stuff we don’t care about. This is exactly what you’d be staring at if you were about to start writing custom parsing logic. You’d probably reach for Beautiful Soup, build a bunch of CSS selectors, clean the text, handle missing fields, and cross your fingers the site doesn’t change next week. That approach works, but it means every new website needs its own parser, its own edge cases, and its own maintenance.
We’re not doing that. We’ll send the raw HTML to Ernie 5.1 along with a description of the schema we want back. In my case, I only care about a few fields: company name, job title, salary range, location, and tech stack. As long as the model can consistently produce that schema, it doesn’t matter how messy the original page is.
The Production Problem: When JSON Isn’t Quite JSON
Now, there’s a problem you’ve probably hit if you’ve tried building AI-powered pipelines before. You ask the model for JSON, and instead of giving you just the JSON, it says something like, “Sure, here’s the structured data you requested.” Then a line break, maybe a markdown code fence, and finally the JSON object. It looks fine to a human. But your application immediately crashes because json.loads expects raw JSON, not a friendly introduction.
That’s not a small issue. When your output feeds directly into another service, a database, or an automation pipeline, consistency matters just as much as accuracy. The less cleanup code you have to write after the model responds, the more reliable the whole pipeline becomes.
Ernie 5.1 has a feature that solves this elegantly: dialogue prefix continuation. The idea is simple. Instead of only sending user messages, you also append one final assistant message containing the exact beginning of the response you want. In our case, that’s an opening square bracket. Then you set prefix to true. What this does is force the model to continue generating from that exact point. So instead of deciding how to start its answer, it immediately begins writing the JSON array. No introduction, no markdown code block, no extra explanation. Just the data your application is expecting.
Here’s how that looks in the API call:
response = client.chat.completions.create(
model="ernie-5.1",
messages=[
{"role": "user", "content": f"Extract job listings from this HTML: {html}"},
{"role": "assistant", "content": "[", "prefix": True}
]
)
That tiny "[" and the prefix flag remove an entire class of post-processing headaches. The model immediately dives into the structured output. You get parseable JSON every time.
From Raw HTML to Database-Ready JSON in One Shot
Let’s see this actually work. I run the pipeline with a messy job listing page as input. The model ignores all the unnecessary markup, picks out the relevant information, and returns a clean JSON object. Something like:
[
{
"company": "Acme Corp",
"title": "Senior Backend Engineer",
"salary_range": "120k - 150k",
"location": "Remote",
"tech_stack": ["Python", "AWS", "PostgreSQL"]
}
]
That’s ready to be inserted into a database, loaded into a Pandas dataframe, or served through an API immediately. I didn’t write a single CSS selector for this particular website. I didn’t handle edge cases where the salary was missing or the location was formatted oddly. The model figured all of that out.
Of course, one successful example doesn’t prove much. So I make the input harder. I throw in a completely different layout from another site, maybe even a chain of customer support emails where the relevant details are buried inside plain text threads. The nice thing is that the pipeline doesn’t really change. As long as I keep the output schema the same, I only need to swap out the input and update the prompt describing what fields I want extracted. That flexibility is what makes this genuinely useful. You’re no longer writing a new parser every time the input changes. You’re defining the structure you want and letting the model figure out how to map messy, unstructured text into that schema.
Handling Semi-Structured Data at Scale
Think about what this means for projects that need to process lots of different sources. You might have product catalogs from suppliers where each one uses a different format. Or financial reports that all contain the same kind of figures but laid out in wildly different tables. Writing a bespoke parser for each one is slow and brittle. With a universal pipeline, you describe the fields you want (product name, price, SKU, stock level) and let the model handle the extraction. The heavy lifting shifts from code logic to prompt design and schema definition.
Trade-Offs to Keep in Mind
This approach isn’t a magic wand. There are a couple of real constraints.
First, getting set up with Ernie 5.1 requires a Baidu account and going through the Qianfan registration process. It’s a one-time setup, but compared to some other providers where you can just grab an API key in 30 seconds, it’s a little extra friction. Not a dealbreaker, just something to plan for.
Second, Ernie 5.1 is currently a text-only model. That’s perfectly fine for workflows where you’re processing HTML, emails, logs, or other text documents. But if your pipeline depends on screenshots, scanned PDFs, charts, or other visual information, you’ll need an OCR or vision model upstream to extract the text before you can feed it into Ernie. For the kind of scraping and data extraction we’re talking about, that’s rarely an issue. Most web data you care about is already in the HTML.
The biggest consideration is architectural. You’re replacing deterministic parsing rules with a probabilistic model. That means you need to build in some validation on your end. You’ll want to check that the returned fields match the expected types, handle missing fields gracefully, and maybe set up retries with lower temperature if you get unexpected results. But honestly, that’s not very different from dealing with real-world scraped data where fields often come back malformed anyway.
Cost: What Makes This Practical for Production
This is where Ernie 5.1 really stands out for a data extraction workflow. With traditional scrapers, your cost is developer time: writing and maintaining parsers. With AI extraction, your cost shifts to API calls. If you’re building a SaaS that processes thousands of web pages every month, you’re sending millions of tokens through the model. Premium APIs can become surprisingly expensive once you start scaling those numbers.
Ernie 5.1 is priced much more aggressively. When you compare token costs for large-scale data extraction, it stays low enough that you can realistically build it into a production application instead of just using it for occasional automation. The conversation changes from “this is a cool experiment” to “this is actually cheaper than dedicating an engineer to parser maintenance for a month.”
For me, that’s the interesting part. It’s not about replacing traditional parsers in every situation. If you’re scraping the same stable website every day, a well-written parser might still be the better choice. But when you’re dealing with messy, constantly changing, semi-structured data where writing and maintaining custom extraction logic quickly becomes more work than it’s worth, this pipeline gives you a powerful alternative.
Points clés à retenir
- The real pain of scraping isn’t downloading pages. It’s turning messy HTML into clean, structured fields, and then maintaining those parsers as sites change.
- A universal AI data pipeline lets you define an output schema once and let the model handle extraction, regardless of the input’s layout.
- Ernie 5.1 integrates with the standard OpenAI Python SDK, so you only change the base URL and model name to get started.
- Using dialogue prefix continuation (appending
"["withprefix: true) forces the model to output raw JSON with no extra text, making it safe forjson.loadsimmediately. - This approach works on everything from job listings to customer support emails, as long as you describe the fields you want and keep the schema consistent.
- Setup requires a Baidu account and Qianfan registration, and Ernie 5.1 is text-only, so visual data needs an OCR step first.
- Pricing is aggressive enough that you can use it in production for large-scale data extraction without the API costs spiraling out of control.
If you want to try building this yourself, you can get started with Ernie 5.1 through Baidu’s Qianfan platform. The API is OpenAI SDK compatible, so if you’ve already built AI applications before, getting an existing project running with Ernie 5.1 is pretty straightforward. I’d also encourage you to experiment beyond the basic job listing example. Try feeding it product catalogs, scraped documentation, financial reports, or whatever messy data your own application deals with. That’s where this workflow becomes the most useful because you spend less time writing parsers and more time building the actual product.
