最近开始学Python的爬虫,是在这个博客跟着学习的,该博主用的是Python 2.7版本,而我使用的是3.5版本,很多不兼容的地方,不过没关系,自己改改就好了。

我们想针对网站的内容进行筛选,只获取自己感兴趣的部分。比如你想在XX网站把小黄图筛选出来,打包带走。这里只做简单的实现,以百思不得姐上的段子(纯文本)为例。我们想要实现如下功能:

  • 批量下载若干页段子到本地文件中
  • 按下任意一键,开始阅读下一条段子

1. 获取网页代码

导入urllib的相关库,Python 3中应该这样写:

import urllib.request
import urllib.parse
import re

re库是正则表达式(Regular Expression),后面作匹配时会用到。

百思不得姐的段子页面url ='http://www.budejie.com/text/1',这里末尾数字1代表此为第一页。通过以下代码就能返回网页内容。

    req = urllib.request.Request(url)
    # 添加headers 使之看起来像浏览器在访问
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 '
                                 '(KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36')
    response = urllib.request.urlopen(req)
    # 得到网页内容,注意必须使用decode()解码
    html = response.read().decode('utf-8')

print(html)的话,就是如下所示的内容:

这能看?段子呢?我们想要的段子呢?!

哦对了headers这样查看。

按F12,然后...看图吧

2. 正则匹配提取段子

要想筛选符合普通人阅读的内容(如果还带着html标签那还咋读是不),成功提取出段子,为此我们需要一些既定的模式去和网页全部内容进行匹配,将模式下匹配成功的对象返回。我们使用强大的正则表达式进行匹配(Regular Expression),相关语法可以看这里

仅仅针对本例中的网页内容,先看看我们需要的段子对应了网页中的什么内容。

可以看到段子被<div class="j-r-list-c-desc">(我们要的内容)</div>这样的标签所包围,只需要指定相应规则提取出来即可!上图可以看出段子正文前后是有很多空格的,需要匹配进去。

pattern = re.compile(r'<div class="j-r-list-c-desc">\s+(.*)\s+</div>')
result = re.findall(pattern, html)

通过re库的compile函数制定规则。

  • \s+可以匹配一个或更多的空格
  • .匹配除开换行符\n外的所有字符。

现在我们得到了匹配后的结果,来看下。

Bingo!提取出来了不是?!

可是我们发现里面还有些讨厌的<br />。没关系,写几行代码的事。这里就不再展示去掉后的内容,自行脑补哈哈。

    for each in content:
        # 如果某个段子里有<br />
        if '<br />' in each:
            # 替换成换行符并输出
            new_each = re.sub(r'<br />', '\n', each)
            print(new_each)
        # 没有就照常输出
        else:
            print(each)

这里content是我们通过re.findall()返回的列表。

至此,我们成功得到我们想看的段子了!如果想要下载到本地呢?

3. 下载段子到本地

通过定义一个save()函数即可,num参数用户自定,想下载最近100页的内容都没问题!里面还有些变量没有提到,最后会给出源代码。

# num是指定网页页数
def save(num):
    # 写方式打开一个文本,把获取的段子列表存放进去
    with open('a.txt', 'w', encoding='utf-8') as f:
        text = get_content(num)
        # 和上面去掉<br />类似
        for each in text:
            if '<br />' in each:
                new_each = re.sub(r'<br />', '\n', each)
                f.write(new_each)
            else:
                f.write(str(each) + '\n')

下载到本地文档后如下图所示

4. 逐条读取段子

段子太多,琳琅满目。可我们只希望一条条阅读。通过按下键盘任意键可以切换到下一条,直到读取到最后一条程序才结束,或者通过设置一个退出键随时退出程序,比如设定q键退出。这里把全部代码给出。

import urllib.request
import urllib.parse
import re

pattern = re.compile(r'<div class="j-r-list-c-desc">\s+(.*)\s+</div>')

# 返回指定网页的内容
def open_url(url):
    req = urllib.request.Request(url)
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 '
                                 '(KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36')
    response = urllib.request.urlopen(req)
    html = response.read().decode('utf-8')
    return html

# num为用户自定,返回的是所有页的段子列表
def get_content(num):
    # 存放段子的列表
    text_list = []
    for page in range(1, int(num)):
        address = 'http://www.budejie.com/text/' + str(page)
        html = open_url(address)
        result = re.findall(pattern, html)
        # 每一页的result都是一个列表,将里面的内容加入到text_list
        for each in result:
            text_list.append(each)
    return text_list

# num是指定网页页数
def save(num):
    # 写方式打开一个文本,把获取的段子列表存放进去
    with open('a.txt', 'w', encoding='utf-8') as f:
        text = get_content(num)
        # 和上面去掉<br />类似
        for each in text:
            if '<br />' in each:
                new_each = re.sub(r'<br />', '\n', each)
                f.write(new_each)
            else:
                f.write(str(each) + '\n')

if __name__ == '__main__':
    print('阅读过程中按q随时退出')
    number = int(input('想读几页的内容: '))
    content = get_content(number + 1)
    for each in content:
        if '<br />' in each:
            new_each = re.sub(r'<br />', '\n', each)
            print(new_each)
        else:
            print(each)
        # 用户输入
        user_input = input()
        # 不区分大小写的q,输入则退出
        if user_input == 'q' or user_input == 'Q':
            break

演示一下,效果是这样的。

虽然功能很鸡肋,不过作为初学我还是很满意了,有兴趣才能深入下去嘛!爬虫可不仅仅如此而已,以后会学习更加高级的功能。


by @sunhaiyu

2016.8.15

最新文章

  1. C#与C++的发展历程第一 - 由C#3.0起
  2. The import javax.servlet cannot be resolved
  3. 简单两句话解释下prototype和__proto__
  4. C-基本语法与运算
  5. 【PRML读书笔记-Chapter1-Introduction】1.6 Information Theory
  6. Socket Programming in C#--Introduction
  7. Linux下OpenSSL的安装与使用
  8. 清除HTML中的特殊字符
  9. UVa 12563 Jin Ge Jin Qu hao【01背包】
  10. 基于Qt的开源音乐播放器(CZPlayer)
  11. C#快速学习笔记(译)
  12. C#学习第三天
  13. Sicily connect components in undirected graph
  14. Postman测试上传文件
  15. MySQL技术内幕读书笔记(六)——索引与算法之全文索引
  16. 项目(四)DHCP服务配置
  17. flume监控
  18. T-SQL 之 事务
  19. WEB安全 魔术引号及注入类型
  20. 使用for in 循环数据集

热门文章

  1. centos 6.6 ios镜像文件 下载 官网和阿里云两种方式教你下载
  2. phpcms V9 后台验证码图片不显示
  3. Window文件目录挂载(mount)到linux系统目录下
  4. Navigation Controller 创建方法
  5. Gitlab维护记录
  6. 【No JSON object could be decoded】问题解决
  7. 流行框架angular
  8. ORM的概念, ORM到底是什么
  9. ansible学习之路
  10. synchronized的作用