从零开始:python实现爬取知乎热榜(随缘更新完善)

  • 获取URL
  • 获取HTML
  • 解析HTML

获取URL

首先要知道URL是什么:
URL: Uniform Resource Identifier,即统一资源标识符。
URL: Uniform Resource Locator,即统一资源定位符。
平常基本用的都是URL,平常访问的网址链接都可以理解为URL。 例如https://www.baidu.com,就是你想要去访问的网页。当然你要访问的更详细的,例如本文的知乎热榜:https://www.zhihu.com/hot

获取HTML

HTML称为超文本标记语言,是一种标识性的语言。也就是访问网页得到的数据,都存放在HTML中,CSS,JS可以去了解一下。
有了URL,直接用python取访问是可能会被封IP的,所以就要用python来模拟浏览器取访问这些网页,这时就需要用到user-agent和cookie。user-agent存放的是浏览器的版本,cookie用来保持登陆之后连续访问多次网站而不需要反复登录。邮件检查或者是f12,在Network选项卡下面的众多记录中随便点进去,找到user-agent和cookie,
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
后面需要的时候复制下来(cookie是经常更新的)。

原材料就足够了,现在需要进行烹饪了。

requests

通过以上的原材料来获取HTML,就需要用到 requests 包

pip install requests

安装成功后就可以进行编码了。

import requests
url = 'https://www.zhihu.com/hot'
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36',
    'cookie':"""cookie要用自己的并且经常要更新"""
}
response = requests.get(url,headers=headers)
if response.status_code == 200:
    html = response.text
print(html)

首先要将之前的原料放到一个名为headers的字典里面,然后通过requests 的 get() 函数来获取到URL的内容。通过if语句来判断访问是否成功,状态码为200代表访问成功。但是访问返回的数据是HTML类型的,通过 .text 转化为文本格式。这样就获得了知乎热榜的内容,仔细观察就能看到热榜的问题在此之中,然后下一步就可以进行内容的提取了。

解析HTML

此次的解析库我使用的是较为普遍的 XPath,稍后有时间再更新其他方法。
XPath 提供了非常简洁明了的路径选择表达式,超过100个内建函数,几乎可以定位所有想要的节点。
基础的XPath常用规则:

表达式描述
nodename选取此节点的所有子节点
/从当前节点选取直接子节点
//从当前节点选取子孙节点
.选取当前节点
选取当前节点的父节点
@选取属性

示例如下:

//title[@lang='eng']

这就是一个XPath规则,代表选择所有名称为title,同时属性lang的值为eng 的节点。
后面会通过python的lxml库,利用XPath进行HTML解析。

准备工作

pip install lxml

就这篇博客的目的来讲,这里只说一下获取知乎热榜的问题所需要的东西。仔细观察之前获取到的HTML,然后就会发现,知乎热榜的问题,都存放在h2。这里建议从开发者模式中依次寻找,找到对应的标题所对应的具体的HTML,因为一个标题会对应很多的相同的字符,在HTML中,这里我找到的实在 h2 中(后续知乎可能会更新,我看过很多的代码,再次自己实现,就会有很多问题,找不到之类的,建议自己实际再找一遍)。
在这里插入图片描述
然后就可以根据自己需要的节点来进行定位,获取数据。
首先要进行的准备工作就是:

from lxml import etree

这里先导入lxml库的etree模块,然后调用HTML类进行初始化,这样就构造了一个XPath解析对象,etree 可以自动修正HTML,比如某些节点没有闭合。但是调用tostring之后输出的修正后的HTML代码,结果是bytes类型的,这里可以利用decode()方法将其转化为str类型。示例如下:

from lxml import etree
html = etree.HTML(html)
result = etree.tostring(html)
print(result.decode('utf-8'))
results = html.xpath('//h2/text()')

这里就可以得到知乎热榜的问题了。
在这里插入图片描述
当然,可以遍历输出,之后的就是字符串操作的范畴了。
附完整代码:

import requests
from pyquery import PyQuery as pq
from lxml import etree

url = 'https://www.zhihu.com/hot'
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36',
    'cookie':"""写自己的,很重要"""
}
response = requests.get(url,headers=headers)
if response.status_code == 200:
    html = response.text
print(html)
html = etree.HTML(html)
result = etree.tostring(html)
print(result.decode('utf-8'))
results = html.xpath('//h2/text()')
count = 0
for result in results:
    print(result)
    count += 1
print(count)

在这里插入图片描述
有关解析库XPath的学习可以参考我的另一篇文章:XPath解析库的学习

2019.10.21更新

对于之前获取到的知乎热榜的问题,我又进行了下一步的更新,这次更新的结果是,将知乎热榜的内容进行了全部爬取,爬取过程变得简单,但是由于个人比较愚笨,花了较长时间对内容进行了优化,结果是将50个问题按照每个问题为划分,一个问题为一个列表,50个问题又组成了一个列表,以便后续的数据分析,结果展示:

[[问题1],[问题2],[问题3],[问题4],[问题5],[问题6]...]

另外我将函数进行了封装,阅读性更强。
由于知乎热榜的每个问题的内容不同,有的有问题简介,有的没有,所以比较乱,当然可以按照其他方式进行分割,我这里使用的是索引方式。(提示:我这里爬取到的结果每个问题都是不同的,但是每个问题开头都是数字,结尾都是“分享”,可以从这里入手,但是我试了几次失败了,如果哪位大神解决了这个问题,可以给我一些建议。

  1. 获取网页内容
  2. 获取索引
  3. 处理结果

我分为了以上三部分,总结代码如下:

# -*- coding: utf-8 -*-
# @Time : 2019-10-11 9:35
# @Author : Ru
import requests
from lxml import etree

def get_content(url,headers):
    """
    根据url,headers来获取网页内容
    :param url:
    :param headers:
    :return:content
    """
    response = requests.get(url,headers=headers)
    if response.status_code == 200:
        html = response.text
    html = etree.HTML(html)
    content = html.xpath('//section//text()')
    return content

def get_index(content):
    """
    获取索引
    :param content:
    :return:index_list
    """
    index_list = []
    for i in range(1,51):
        i = str(i)
        index_list.append(content.index(i))
        return index_list

def return_result(content,index_list):
    """
    处理结果
    :param content:
    :param index_list:
    :return:result
    """
    result = []
    for num in range(60):
    #60是因为循环的次数要大于50或者是51,具体哪个我也不清楚,就索性60简单些
        for i in range(len(index_list)):
            pri_lsit = []
            a = index_list[i]
            if index_list[i] == index_list[-1]:
                b = len(content)
            else:
                b = index_list[i + 1]
            for i in range(a, b):
                pri_lsit.append(content[i])
            # print(pri_lsit)
            result.append(pri_lsit)
    print(result)
    return result

if __name__ == '__main__':
    url = 'https://www.zhihu.com/hot'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36',
        'cookie': """还是注意一点,cookie要用自己的,这一点很重要"""
    }
    content = get_content(url,headers)
    index_list = get_index(content)
    return_result(content,index_list)

结果展示:
处理结果展示

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值