Python-101
  • 介绍
  • KickOff Party
    • 1.1 教学目的
    • 1.2 软件和工具
    • 1.3 课前自学
  • Python 简介
    • 2.1 数据工程介绍
    • 2.2 Python 介绍
    • 2.3 Python 语法
    • 2.4 Python 请求
    • 2.5 Python 语法进阶
  • 爬虫
    • 3.1 HTML
    • 3.2 爬虫实战
    • 3.3 选学:JSON 简介
    • 3.4 选学:爬虫的难点
  • 数据处理
    • 4.1 初见数据处理
    • 4.2 数据处理应用实例
    • 4.3 选学:Pandas
  • Demo练习
  • 大作业
  • 分享与后续学习建议
Powered by GitBook
On this page
  • 总结规律
  • 网站的结构
  • 全站爬虫的构造

Was this helpful?

  1. 爬虫

3.2 爬虫实战

Previous3.1 HTMLNext3.3 选学:JSON 简介

Last updated 6 years ago

Was this helpful?

Cooking time: 30 mins active / 45 mins passive

Tasks For Instructors: 讲师讲解和演示该节内容,若相关内容认为需要教练辅助,请讲师灵活应变。

  • 如果网站提供了 API,那么用 API 比从网页解析要更简单。

  • 如果 API 不能满足需求,再去考虑做网页爬虫。

  • 总结网址的规律,写成循环。

总结规律

例如贴吧的一个帖子,首页,第二页,第三页的网址分别如下:

那么只要我们知道一共有多少页,然后循环迭代 pn=...,就能遍历所有的页面。我们可以用 range(from, to) 构造一个迭代器,从 from 迭代到 to - 1:

for page in range(1, 4)
    url = f"https://tieba.baidu.com/p/1433563243?pn={page}"

网站的结构

网站由一个或者多个网页组成,各个网页之间以超链连接起来,画成图会像这样:

全站爬虫的构造

爬虫分为定向爬虫和全站爬虫。

定向爬虫只关注特定的内容,全站爬虫的目标却是爬下整个网站。

全站爬虫一般应用于搜索引擎、发现新内容、保存网络快照等目的。

为了实现爬虫的连续工作,我们可以把任务分解开来。

编程中如何分解任务?一种思维模式是:

  • 可以先考虑简单的、特殊的情况。

  • 把简单情况的代码写出来后,再把它改成更通用的情况 -- 例如改成一个函数。

  • 把分解的函数组装起来,调试完成任务。

最简单的状况,网站只有一个页面的时候,我们回忆 requests 的用法,直接发出请求就可以了。

稍微复杂一点的情况,网站有一个入口页和多个次级页面,我们分析入口页的所有链接,得到次级页面的链接爬取汇总。

links = BeautifulSoup(page).select('a')
urls = []
for link in links:
    urls.append(link['href'])

再复杂一点,网站的次级页面上还有到更次一级的页面的链接,我们可以把上面的代码提炼成一个函数:

def extract_links(page):
    links = BeautifulSoup(page).select('a')
    urls = []
    for link in links:
        urls.append(link['href'])
    return urls

把请求网页的代码也组合到一起:

def get_page(url):
    page = requests.get(url)
    urls = extract_links(page.text)
    for sub_url in urls:
        get_page(sub_url)

这个函数调用了自己,叫做 递归函数。

上面的代码还有一些问题,如果子页面恰好链接到了父页面,它就停不下来了(实际上会出现一个栈溢出错误)。我们可以用集合来保证不会爬取相同的网页。

crawled = set()
def get_page(url):
    if url in crawled:
        return # 下次碰到相同的网页,它就不会再爬取了
    crawled.add(url)
    page = requests.get(url)
    urls = extract_links(page.text)
    for sub_url in urls:
        get_page(sub_url)
https://tieba.baidu.com/p/1433563243
https://tieba.baidu.com/p/1433563243?pn=2
https://tieba.baidu.com/p/143b3563243?pn=3