社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python 爬虫小课 1-9 宝妈程序媛福利-育儿网问答数据抓取

梦想橡皮擦 • 4 年前 • 1025 次点击  

爬虫百例专栏连载已经结束,欢迎订阅 🙈100 篇爬虫文章合计 29.9 元,每篇只需 2.9 毛钱 🙈

🌹 橡皮擦 叨叨 🌹
本专栏为爬虫小课系列,周更 3+篇,专栏合计 9 篇文章,本专栏所有案例都将采用 requests 库编写,通过 9 个案例,让你深入理解 requests 库。
以上就是本系列专栏的核心目标。

本系列课程需要一定的 Python 语法基础,数据匹配将采用 Python 自带的 re 模块,故对正则表达式有一定的基础要求。
关于爬取环境的需求,Python3.5 以上版本,安装 requests 模块。

爬虫前的分析

类别页面分析

本次爬虫小课要爬取的的网站为育儿网( http://ask.ci123.com/ ) 的问答模块,我们要采集一下红框内的资料。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

对于该网站涉及的问题类型非常多,具体分类可以通过上述链接左侧的菜单获取到。如下图所示区域:

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

在这里需要略微分析一下,分类地址的规律,如果没有规律,那第一步就先获取一下所有的分类地址,鼠标点击各链接发现,分类列表页链接如下:

http://ask.ci123.com/categories/show/2
http://ask.ci123.com/categories/show/3
http://ask.ci123.com/categories/show/4
http://ask.ci123.com/categories/show/{类别ID}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

在这里先不要下结论,说 ID 是依次递增的,写爬虫程序如果过早的假定一定的规则,很容易出现数据丢失的情况,所以尽量都尝试一遍。

在这里也可以直接通过查看网页源码,看一下所有的地址,当然看完之后还是为了我们可以爬取到。最终查阅到所有的地址都为 http://ask.ci123.com/categories/show/{类别ID} 形式,只是最后的类别 ID 不是连续的。到这里问题分类分析完毕。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

问题列表页面分析

下面需要寻找列表页相关规律,点击任意类别之后,可以查阅到,页面数据样式都如下图所示:

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

首先要做的第一件事请,就是查找分页规律,找到分页区域,鼠标依次点击分页,获取不同的分页地址。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

最后找到其规律链接地址如下:

http://ask.ci123.com/categories/show/4/all?p={页码}
  • 1
  • 1

有页码规律还不够,还需要找到末页,在源码中简单检索,找到末页对应的页码即可。

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

到此爬虫前的分析分析完毕了,下面开始进行爬虫逻辑编码环节,也就是整理自己的思路。

逻辑编码(伪代码)

育儿网爬虫分为如下步骤:

  1. 通过 http://ask.ci123.com/ 页面,获取所有的分类页面地址
  2. 循环所有的分类页面地址
  3. 获取每个分类对应的列表页面,并获取总页码
  4. 从一开始循环到总页码
  5. 上一步循环过程中过去每一页待爬取的数据

思路整理完毕,编码环节其实就是一个简单的实现过程。

爬虫正式编码

request 库 get 方法说明

对于 requests 库来说,导入并快速应用是非常容易的,先通过抓取分类页面源码来看一下基本使用。

import requests

url = "http://ask.ci123.com/"

# 抓取分类页面
def get_category():
    res = requests.get("http://ask.ci123.com/")
    print(res.text)


if __name__ == "__main__":
    get_category()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

以上代码中最核心的方法就是 requests.get()了,该方法为 requests 模块通过 get 方式获取网站源码,该方法中的参数说明如下:

必选参数 url

requests.get(url="http://ask.ci123.com/")

  • 1
  • 2
  • 1
  • 2

传递 URL 参数

通过该参数可以构造出如下格式 https://www.baidu.com/s?wd=你好&rsv_spt=1&rsv_iqid=0x8dd347e100002e04
格式如下:

import requests
payload = {'key1':


    
 'value1', 'key2': 'value2'}
res = requests.get(url="http://ask.ci123.com/", params=payload)
print(res.url)
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

key1 为键名,value1 为键值。

定制请求头

在爬虫爬取的过程中,我们将尽量将爬虫模拟成真实的用户通过浏览器访问网站,所以很多时候需要定制浏览器请求头。格式如下:

import requests
payload = {'key1': 'value1', 'key2': 'value2'}
headers = {
    'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)'
}
res = requests.get(url="http://ask.ci123.com/",
                   params=payload, headers=headers)
print(res.url)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其中 headers 中可以配置更多的内容,本篇博客不做展开,只需要先记住 headers 参数即可。

Cookie

Cookie 在很多爬虫程序中属于必备内容,这里有时会存储加密信息,有时会存储用户信息,格式如下:

import requests
payload = {'key1': 'value1', 'key2': 'value2'}
headers = {
    'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)'
}
cookies = dict(my_cookies='nodream')
res = requests.get(url="http://ask.ci123.com/",
                   params=payload, headers=headers, cookies=cookies)
print(res.text)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

禁用重定向处理

有些网站会携带重定向源码,在爬取的时候需要禁止网格员自动跳转,代码如下:

r = requests.get('http://github.com', allow_redirects=False)
  • 1
  • 1

超时

对于一个网络请求,有时会出现无法请求到的情况,这部分在官方手册高级部分有相应的说明,不过对于初学者可以先进行忽略超时的高级用法。

为防止服务器不能及时响应,大部分发至外部服务器的请求都应该带着 timeout 参数。在默认情况下,除非显式指定了 timeout 值,requests 是不会自动进行超时处理的。如果没有 timeout,你的代码可能会挂起若干分钟甚至更长时间。

常规代码如下:

import requests
payload = {'key1': 'value1', 'key2': 'value2'}
headers = {
    'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)'
}
cookies = dict(my_cookies='nodream')
res =


    
 requests.get(url="http://ask.ci123.com/",
                   params=payload, headers=headers, cookies=cookies, timeout=3)
print(res.text)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

高级部分参数

对于 get 方法,还有一些参数,在后续的博客中我们可能会用到,例如:

  • SSL 证书验证 (verify)
  • 客户端证书(cert)
  • 事件钩子(hooks)
  • 自定义身份验证(auth)
  • 流式请求(stream)
  • 代理(proxies)

以上参数都会出现在 get 方法中,所以 requests 库是一个非常非常强大的库。

获取所有的分类页面地址

有了上述详细的说明,在使用 requests 库去获取网页中的内容就变得简单一些了。这里需要有 Python 基础知识中 re 模块的使用与正则表达式的基础。具体的爬取代码如下:

import requests
import re

url = "http://ask.ci123.com/"
headers = {
    'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)'
}
# 抓取分类页面
def get_category():
    res = requests.get("http://ask.ci123.com/", headers=headers)
    pattern = re.compile(
        r'<li><a href="/categories/show/(\d+)">', re.S)
    categories_ids = pattern.findall(res.text)
    print(f"获取到的分类ID如下:",categories_ids)

if __name__ == "__main__":
    get_category()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

循环所有的分类页面地址

在上述代码中通过 re库 的 findall 方法获取了所有的分类编号,用来拼接后续的待爬取页面。获取到 IDS 之后,就可以通过循环的方式获取到所有的列表页面了,具体如下:

# 抓取分类页面
def get_category():
    res = requests.get("http://ask.ci123.com/", headers=headers)
    pattern = re.compile(
        r'<li><a href="/categories/show/(\d+)">', re.S)
    categories_ids = pattern.findall(res.text)
    print(f"获取到的分类ID如下:", categories_ids)
    for cate in categories_ids:
		# 下述代码中有get_list()函数对应的代码
        get_list(cate)
        time.sleep(1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

上述代码为了防止被反爬,需要增加一个延时处理, time.sleep()

获取每个分类对应的列表页面,并获取总页码

打开列表页面,首要目的先获取到总页码,本次实现的案例获取的页码途径比较简单,在列表页存在一项,数据直接在源码中可以看到,故直接抓取即可。

def get_list(cate):
    # 获取总页码,循环抓取所有页

    res = requests.get(
        f"http://ask.ci123.com/categories/show/{cate}", headers=headers)

    pattern = re.compile(
        r'<a class="list_last_page" href="/categories/show/\d+/all\?p=(\d+)"', re.S)
    totle = pattern.search(res.text).group(1)
    for page in range(1, int(totle)):
        print(f"http://ask.ci123.com/categories/show/{cate}/all?p={page}")
        time.sleep(0.2)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

从 1 开始循环到总页码

本部分代码比较容易,已经在上述代码实现。结果如图所示:

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取

本案例收尾环节

后续的内容就变得非常容易了,对每页数据进行分析,并进行存储数据操作,下述代码未编写存储部分,抓取部分代码已经填写完整,其中存在一个非常大的正则表达式,可以参考一下,如果爬取数据不是很严格,大量的使用 .*\s 这些常见元字符即可。

import requests
import re
import time

url = "http://ask.ci123.com/"
headers = {
    'user-agent': 'Baiduspider-image+(+http://www.baidu.com/search/spider.htm)'
}


def get_detail(text):
    # 该函数实现解析页面数据,之后存储数据
    pattern = re.compile(r'<li>[.\s]*<a href="/questions/show/(\d+)/" title="(.*?)" class="list_title" target="_blank" >.*?</a>\s*<span class="list_asw">(\d+)<font>.*?</font></span>\s*<a class="list_author"  href="/users/show/\d+" title=".*?">(.*?)</a>\s*<span class="list_time">(.*?)</span>\s*</li>')
    data = pattern.findall(text)
    print(data)
    # 数据存储代码不在编写


def get_list(cate):
    # 获取总页码,循环抓取所有页

    res = requests.get(
        f"http://ask.ci123.com/categories/show/{cate}", headers=headers)

    pattern = re.compile(
        r'<a class="list_last_page" href="/categories/show/\d+/all\?p=(\d+)"', re.S)
    totle = pattern.search(res.text).group(1)
    for page in range(1, int(totle)):
        print(f"http://ask.ci123.com/categories/show/{cate}/all?p={page}")
        res = requests.get(
            f"http://ask.ci123.com/categories/show/{cate}/all?p={page}", headers=headers)

        time.sleep(0.2)
        # 调取列表页数据提取函数
        get_detail(


    
res.text)


# 抓取分类页面
def get_category():
    res = requests.get("http://ask.ci123.com/", headers=headers)
    pattern = re.compile(
        r'<li><a href="/categories/show/(\d+)">', re.S)
    categories_ids = pattern.findall(res.text)
    print(f"获取到的分类ID如下:", categories_ids)
    for cate in categories_ids:
        get_list(cate)
        time.sleep(1)


if __name__ == "__main__":
    get_category()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

广宣时间

如果你想跟博主建立亲密关系,可以关注博主,或者关注博主公众号“ 非本科程序员 ”,了解一个非本科程序员是如何成长的。
博主 ID: 梦想橡皮擦 ,希望大家点赞、评论、收藏

Python 爬虫小课 1-12 宝妈程序媛福利-育儿网问答数据抓取
爬虫百例教程导航链接 : https://blog.csdn.net/hihell/article/details/86106916

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/74832
 
1025 次点击