云计算百科
云计算领域专业知识百科平台

写爬虫之前先别写代码:四步从零爬一个网站

写爬虫之前先别写代码:四步从零爬一个网站

新手拿到一个"把这个榜单抓下来"的任务,通常第一件事是打开编辑器。

这一步就错了。

爬到一半抓不到东西、抓到乱码、翻页翻崩、跑第二次被封——这些问题,九成不是代码写错了,是开工之前没搞清楚三件事:

  • 数据到底在不在页面源码里
  • 它长什么样(结构)
  • 这个站允不允许你抓
  • 这篇按真实流程走一遍:从一个网址,到一份能打开的 CSV。文中的代码我全部跑过,输出贴在下面。

    先看完整脚本

    import csv
    import time

    import requests
    from lxml import etree

    BASE = 'https://quotes.toscrape.com' # 专门给爬虫练习用的站点
    rows = []

    for page in range(1, 4):
    url = f'{BASE}/page/{page}/'
    r = requests.get(url, timeout=15, headers={'User-Agent': 'Mozilla/5.0'})
    r.raise_for_status()

    html = etree.HTML(r.text)
    for q in html.xpath('//div[@class="quote"]'):
    rows.append({
    '作者': q.xpath('./span/small[@class="author"]/text()')[0],
    '内容': q.xpath('./span[@class="text"]/text()')[0],
    '标签': ','.join(q.xpath('./div[@class="tags"]//a[@class="tag"]/text()')),
    })

    time.sleep(1) # 每次请求之间停一下,别把人家服务器打疼

    with open('quotes.csv', 'w', newline='', encoding='utf-8-sig') as f:
    writer = csv.DictWriter(f, fieldnames=['作者', '内容', '标签'])
    writer.writeheader()
    writer.writerows(rows)

    print(f'共抓到 {len(rows)} 条')

    我跑出来的实际输出:

    共抓到 30 条

    作者,内容,标签
    Albert Einstein,"“The world as we have created it is a process of our thinking…",change,deep-thoughts,thinking,world

    三页、每页 10 条、共 30 条。下面拆开讲。

    第一步:先判断数据在不在源码里

    打开目标页面,按 F12 → 切到 Elements → 按 Ctrl+F,搜你要的那段文字。

    这个动作决定了后面全部工作,只需十秒。

    搜索结果说明后面怎么做
    搜得到,而且高亮在一个正常标签里 数据在静态源码里 requests 直接拿 HTML,用 XPath 解析
    搜不到 数据是 JS 渲染出来的 去 Network 面板找那个接口
    搜得到,但外层有 <iframe> 内容在嵌套框架里 要单独请求 iframe 的地址

    新手最常犯的错:对着一个 JS 渲染的页面硬写 XPath,写两小时抓不到,然后怀疑自己。

    不是不会写,是这个页面根本没有你要的东西。源码里没有的,XPath 再怎么写也抓不到。

    顺便说:怎么判断"该不该用浏览器自动化"。

    • 数据在 Network 里有个干净的接口 → 用 requests,快、稳、省资源
    • 页面必须滚动/点击才加载,接口还加了签名 → 才轮到 DrissionPage 这类工具

    能不开浏览器就别开。 一个 requests 请求是毫秒级,开个浏览器是几秒,还容易受版本更新影响。

    第二步:定位元素,写选择器

    假设确认了数据在源码里。接下来找容器:

    //div[@class="quote"] ← 每一条的外层容器

    再往下取字段:

    ./span[@class="text"]/text() 内容
    ./span/small[@class="author"]/text() 作者
    ./div[@class="tags"]//a[@class="tag"]/text() 标签

    注意这几点:

    • 开头用 .:./span 表示"在当前这个 div 里面找",//span 是"在整个文档里找"。少了这个点,你取到的永远是第一条。 这个坑几乎每个人都踩过。
    • 用相对路径,不要用浏览器复制的绝对路径(/html/body/div[3]/…),那个页面一改就废。
    • 写完先在 Console 验证:

    $x('//div[@class="quote"]')

    返回 10 个,就对了。返回 0 个,说明名字写错或者是动态渲染。

    第三步:翻页

    先搞清楚翻页的规律。大部分站只有三种:

    类型长什么样怎么处理
    URL 有页码 ?page=2 或 /page/2/ 最简单,for 循环换数字
    "下一页"是个链接 <a rel="next" href="…"> 抓那个 href,循环请求
    滚动加载 / 点按钮 URL 不变,内容变多 去 Network 找分页接口

    先手动点两页,看地址栏变不变。 这一看就知道属于哪种。

    上面脚本用的是第一种。如果是第二种:

    next_url = html.xpath('//li[@class="next"]/a/@href')
    if next_url:
    url = BASE + next_url[0]

    一定要有终止条件。 最常见的事故是:翻到最后一页,next 取不到,代码继续跑,无限循环请求同一个地址——这是被封 IP 最快的方式。

    第四步:存盘

    用 csv 模块,别自己拼字符串:

    import csv

    with open('data.csv', 'w', newline='', encoding='utf-8-sig') as f:
    writer = csv.DictWriter(f, fieldnames=['作者', '内容', '标签'])
    writer.writeheader()
    writer.writerows(rows)

    两个细节:

    1. encoding='utf-8-sig' —— 不加这个,Excel 打开中文是乱码。utf-8-sig 会加一个 BOM 头,Excel 才认。

    2. 内容里有逗号会出问题,但 csv 模块会自己处理 —— 你看我上面的输出:

    Albert Einstein,"“The world as we have created it…",change,…

    内容被自动加了双引号,因为里面有逗号。这就是为什么要用 csv 模块——自己拿 ','.join() 拼,一遇到带逗号的内容整个表格就错位了。

    三个最常见的坑

    坑一:抓到一半报错,前面白跑了

    加保护,并且记录失败项而不是整个崩掉:

    try:
    rows.append({...})
    except IndexError:
    print(f'第 {page} 页有异常,跳过')
    continue

    只写 pass 是不行的——你永远不知道丢了多少。

    坑二:被限流,返回 403 或空内容

    三个动作:

  • 每次请求后 time.sleep(1),别连发
  • 加正常的 User-Agent(很多站直接拒绝默认的 python-requests/2.x)
  • 降低并发,不要一上来开 50 个线程
  • 频率是最容易被忽视的合规问题。 把人家服务器打挂了,比抓不到数据严重得多。

    坑三:明明 XPath 是对的,就是取不到

    按这个顺序排查:

  • 是不是动态渲染(Ctrl+F 搜一下源码)
  • 是不是在 iframe 里
  • class 名是不是动态的(刷新一次看变不变)
  • /text() 只能取直接文字,嵌套标签里的文字要用 //text()
  • 关于合规,说几句实在的

    爬虫是敏感话题,但它的边界其实很清楚。下面这些不是客套话,是红线:

    1. 先看 robots.txt

    https://目标网站/robots.txt

    这是网站明确写给爬虫看的规则。它说 Disallow 的路径,不要抓。

    2. 不要抓这些东西

    • 个人隐私信息(手机号、身份证、住址、聊天记录、通讯录)
    • 需要登录才能看到的内容
    • 付费内容(绕过付费墙是另一回事,性质完全不同)

    3. 控制频率

    加 sleep、别开高并发、别在对方业务高峰跑。"我抓得快"不是本事,是事故。

    4. 数据不要商用、不要转售、不要二次分发

    自己学习、做分析、写论文引用结论可以;把整站数据打包卖出去,那是另一回事。

    5. 不要做的事,技术上都很容易做

    绕过验证码、伪造登录态、强行绕过接口签名校验——这些都不是"技术能力强",是给自己留证据。

    《网络安全法》《数据安全法》和《刑法》第二百八十五条(非法获取计算机信息系统数据罪)都管这块。

    6. 练习请用专门的练习站

    这篇用的 quotes.toscrape.com 就是专门给爬虫练习做的——数据是假的,站方欢迎你来抓。类似的还有 books.toscrape.com、httpbin.org。

    拿真实网站练手,出问题的是你;拿练习站练手,出问题的只有你的代码。

    写在最后

    看完这篇,你会发现真正的工作量不在写代码。

    代码去掉空行二十来行,剩下全是"搞清楚状况":数据在哪、结构是什么、能不能抓、会不会被封。

    新手最容易犯的错,就是把顺序搞反了——先写代码,再调试,最后才发现方向错了。

    正确的顺序是:

    看一眼(Ctrl+F 搜得到吗)
    ↓
    定结构(元素有什么稳定特征)
    ↓
    写选择器(Console 里验证)
    ↓
    加翻页 + 间歇
    ↓
    存盘(csv 模块 + utf-8-sig)

    这五步走顺,你会发现爬虫其实不难——难的是耐心,不是技术。

    成本:🟢 零成本零注册。 全程只用 requests + lxml + 标准库的 csv、time,示例跑的是公开的练习站点,不需要账号、不需要代理、不需要任何付费服务。

    免责声明(请务必读完)

    • 本文用于技术学习,代码示例基于站方专门提供的练习站点,不针对任何真实业务网站。
    • 抓取任何网站前,请先阅读其 robots.txt 与服务条款;对方明确禁止的,不要抓。
    • 不得抓取个人隐私信息,不得抓取需登录或付费才能访问的内容,不得绕过任何技术保护措施。
    • 请控制请求频率,避免对目标服务器造成负担或影响正常用户。
    • 抓取到的数据不得用于商业用途、不得转售或二次分发。
    • 因使用本文代码产生的任何法律后果,由使用者自行承担。
    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 写爬虫之前先别写代码:四步从零爬一个网站
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!