Querying and Analyzing Data in SQLite
spider.py systematically crawls web pages and stores them in a local database, recording both page content and the links between pages.
From Pages to Evidence
A collection of web pages becomes useful for analysis only after the crawler has recorded both the pages and the connections between them. The spider.py program performs that collection: it starts from a URL, fetches a page, extracts links, stores the page and its outgoing links in spider.sqlite, and continues through unvisited links. The resulting database is not just a list of URLs. It is a graph of pages and relationships that can later be queried, analyzed, and visualized.
The Crawl Decision Loop
Each crawl follows a repeating decision pattern. The program begins with a starting URL, visits a page, finds that page's outgoing links, stores the page and its relationships, and then selects another unvisited link. This systematic loop changes a live web of pages into a stored snapshot of the portion that has been collected.
A three-page crawl
Imagine an empty database, a starting URL of http://example.com/, and a request to crawl 3 pages. Trace the records and unvisited links as the crawler proceeds.
Start: The crawler receives the starting URL and has no previously stored pages in the empty database.
Visit the first page: The crawler fetches the starting page, records its URL with a unique page ID, counts its outgoing links, and records relationships from that page to the discovered targets.
Choose another page: The discovered links become candidates in the unvisited collection. The crawler selects an unvisited link and repeats the same process.
Reach the requested count: After three pages have been processed, the requested crawl size has been reached. The database contains the stored page records and the link relationships found during those visits.
The important result is not a predetermined set of URLs. It is the repeated transformation of visited pages and discovered links into persistent page and relationship records.
From Live Content to SQLite Records
The crawler writes to a persistent SQLite file named spider.sqlite. The database contains at least two tables: one for pages and one for links. A page record includes a unique ID, the URL, and the count of outgoing links. A link record stores a source page ID and a target page ID. Together, these records preserve both the page itself and the direction of each connection.
This structure supports questions about direction. You can find the pages that a given page links to by following relationships from its source ID. You can also find pages that link to a given page by looking for relationships with that page as the target ID. The same stored relationships can support network statistics and later visualization.
Incremental Crawling
The database is designed to grow across sessions. When spider.py runs again, it remembers which pages are already stored and skips them. If one session collects 10 pages and a later session requests 20 pages, the later session fetches only the 10 new pages needed to extend the collection. The existing records remain in spider.sqlite, so the second session builds on the first instead of starting over.
Separate Webs, Shared Database
A single database can contain pages discovered from multiple independent starting URLs. For example, one session can begin at http://www.dr-chuck.com/ and another can begin at http://www.wikipedia.org/. The two collections are called separate webs within the program, but their pages and links are stored in the same spider.sqlite file.
The crawler does not maintain a separate visit queue for each starting point. It treats all unvisited links across the webs as one unified collection and randomly selects from that collection. As a result, later visits can interleave pages from the different starting points. The webs may eventually connect through links, or they may remain separate clusters or isolated portions of the stored graph.
Reading the Stored Graph
Once crawling has produced records, querying becomes a way to inspect the graph. Page records can answer questions about URLs and outgoing-link counts. Link records can answer which pages a page points to and which pages point back to it. These are different directions, so analysis should make clear whether it is following a source page outward or searching for incoming links to a target page.
| Question | Record relationship to follow | What it reveals |
|---|---|---|
| Which pages does this page link to? | Source page ID to target page ID | The page's outgoing connections |
| Which pages link to this page? | Target page ID matched from link records | The page's incoming connections |
| How many outgoing links does a page have? | Page record's outgoing-link count | The page's recorded link count |
| Which pages are highly connected? | Page and link records analyzed together | Patterns in the stored graph |
The raw records can also feed later analysis and visualization. Algorithms such as a simplified page rank calculation can use the graph to estimate which pages are central or influential within the collected web. D3 can read the page and link data and render pages as nodes and links as edges, making clusters, hub pages, and isolated pages easier to see.
Mistakes in Crawl Analysis
Treating the database as only a list of URLs.
The connections between pages are stored separately as relationships containing source and target page IDs.
Fix:
Use both page records and link records when analyzing connectivity.Assuming a later crawl starts from an empty database.
The crawler skips pages already in the database and continues with unvisited links.
Fix:
Treat later sessions as incremental growth unless spider.sqlite has been deleted.Keeping separate queues for separate starting URLs.
All unvisited links across the webs are treated as one unified collection.
Fix:
Expect the crawler to select randomly from unvisited links across the stored webs.Confusing outgoing and incoming relationships.
An outgoing count describes links from the page, while incoming links must be found by examining target relationships.
Fix:
Identify whether the analysis starts from a source page or searches for a target page.
Practice the Trace
A database already contains pages from one crawling session. You start spider.py with a different URL and request more pages. Explain what can happen to the stored database, which pages the crawler should skip, and why the next visit may come from either starting web.
Hints
- Separate the ideas of stored pages, unvisited links, and new starting URLs.
- Remember that the database contains both page records and link records.
- The crawler selects from all unvisited links rather than maintaining isolated queues.
What do you think happens?
After one session has stored pages from a first starting URL, what should a later session do when it encounters one of those stored pages?
Reveal answer
Answer: Skip it and continue with an unvisited link
The crawler is additive: it remembers pages already in the database and avoids re-crawling them while continuing incremental collection.
Key Takeaways
- spider.py turns live pages and their outgoing links into a persistent graph stored in spider.sqlite.
- The page table records page IDs, URLs, and outgoing-link counts; the link table records source and target page IDs.
- Repeated sessions extend the database by skipping pages already stored and selecting unvisited links.
- Multiple starting URLs can create separate webs that share one database and one unified collection of unvisited links.
- Queries, graph algorithms, and D3 visualizations can transform the stored records into connectivity insights.
Key Takeaways
- A crawler must collect pages and links before connectivity can be analyzed.
- SQLite stores page information and directed relationships between page IDs.
- Incremental crawling avoids redundant fetching by skipping pages already in the database.
- Independent starting URLs can coexist as separate webs inside one shared database.
- The stored graph supports relationship queries, network analysis, and visualization.