使用Python中的re模块提取页面数据

使用Python语言作为工具进行web数据爬取是一件很轻松的事。正则表达式则是一种可以高速匹配文本的操作,当正则表达式与Python相结合时,也会摩擦出不一样的火花。

本文将通过一个简单的爬虫案例对简书页面进行数据爬取,运用requests模块与re模块。抓取简书首页1000条文章链接与标题。

依赖库

该案例需要导入以下3个Python模块。

  • requests
  • fake_useragent
  • re

其中, requests和fake_useragent并不是Python标准库的模块,使用前可以通过pip安装一下。

pip install requests -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

pip install fake_useragent -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

当然,requests也可以使用urllib代替,主要用来请求页面并返回数据。

fake_useragent的功能为自动生成一个user-agent,当然也可使用自己浏览器的user-agent。

re模块则是Python标准库的正则模块,在本案例中用于过滤数据,关于re模块的使用可以参考笔者之前的文章。

import re
import requests
import fake_useragent

寻找接口

笔者推荐使用Chrome浏览器进行接口排查。

首先进入在Chrome中进入简书首页,按f12进入开发者工具状态,并找到Network选项。

由于页面通过滚轮滑动实现了加载数据,所以笔者认为这是通过Ajax进行了数据渲染。

在Network下有一个XHR的选项,这个选项便是页面中出现的所有Ajax接口。

对爬虫工程师而言,最敏感的单词之一莫过于page,即:页码。没错,在Headers里的Request URL的链接便是我们需要的接口。

构建请求头

关于请求头,我们需要构建:

  • User-Agent:防止被检测为爬虫程序
  • X-Requested-With:Ajax请求头
  • Cookie:添加Cookie是为了爬取推送给本人账号的数据
# 实例化UserAgent对象
user_agent = fake_useragent.UserAgent(use_cache_server=False)

url = 'https://www.jianshu.com/?seen_snote_ids%5B%5D=66169577&seen_snote_ids%5B%5D=70078184&seen_snote_ids%5B%5D=59133070&seen_snote_ids%5B%5D=71131220&seen_snote_ids%5B%5D=69717831&seen_snote_ids%5B%5D=71082246&seen_snote_ids%5B%5D=69512409&seen_snote_ids%5B%5D=66364233&seen_snote_ids%5B%5D=68425069&seen_snote_ids%5B%5D=65829398&seen_snote_ids%5B%5D=70390517&seen_snote_ids%5B%5D=70715611&seen_snote_ids%5B%5D=60025426&seen_snote_ids%5B%5D=69454619&page={}'

# 请求头
headers = {
    # 随机生成1个user-agent
    'User-Agent': user_agent.random,
    'X-Requested-With': 'XMLHttpRequest',
    'Cookie': 'xxxxxxx',
}

# 设置代理(可省略)
proxies = {
    'http': 'http://54.241.121.74:3128',
    'https': 'http://54.241.121.74:3128'
}

需要注意,url链接的page属性使用了{}进行后续页码的传递。

请求页面

首先我们先构建1个全局变量num用来对提取的数据进行计数。

num = 1

接下来便是请求页面了。

# 初始页码
count = 0

# 循环请求页面
while True:
    response = requests.get(
        # 传入页码
        url=url.format(i),
        headers=headers,
        proxies=proxies
    )
    
    count += 1
    
    # 解析页面
    title_and_link = get_data(response.text)
    # 展示数据
    show_data(title_and_link)
    
    # 如果judge为True,代表已经爬取了1000条数据
    if num > 1000:
        break

解析页面

def get_data(text):
    """
    提取页面源码中的信息
    :param text: 页面源代码
    :return: result
    """
    # 生成正则对象
    pattern = re.compile(r'<a class="title" target="_blank" href="(.*?)">(.*?)</a>', re.S)
    # 查找符合上一行正则对象的数据
    result = pattern.finditer(text)
    
    return result

展示数据

def show_data(title_and_link):
    """
    展示数据
    :param title_and_link: 数据
    :return: None
    """
    # 重新声明num
    global num

    for i in title_and_link:
        # 打印数据
        print(f'{num}:https://www.jianshu.com{i.group(1).strip()}', end=' ')
        print(i.group(2).strip())
        num += 1
        if num > 1000:
            print('完成任务!!!')
            break

结语

这个爬虫程序还是比较简单的,毕竟找到接口,就可以一步步的深挖数据。

实际上,这个爬虫程序存在着一些比较显而易见的bug,尤其是当你没有设置Cookie的时候。

没错,由于接口原因,当我们没有设置Cookie时,爬取的数据基本上是重复的,并且Cookie也并不能完美的解决这个问题。当数据量较大时,即使设置了Cookie也会出现重复的数据。

这个bug最直接的解决方案便是更换接口,但这样做也代表着需要重构部分代码(虽然也没多少代码)。确实,通过Chrome的开发者工具查看,其他的接口也是存在的,主要看你能不能找到罢了。此外,使用selenium也是一个不错的选择。此处也体现了爬虫程序的主观性,即实现功能的方法是多种多样的。不过笔者想说的是,既然提到了去重,那怎么能少了Redis呢?

没错,下篇文章便是对上述的爬虫程序进行去重的优化操作。

关于本文的完整代码,可以来笔者的GitHub下获取。

https://github.com/macxin123/spider/blob/master/jianshu/re_jianshu.py

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容