html定位 知乎,从零开始: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,

9a952d7d319f76be91c38b8b069cc3b0.png

26c67d5cb04e47f413b7e3d3480146c8.png8cc5c314fae91857c3f470dc5b4ce7d5.png

后面需要的时候复制下来(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 中(后续知乎可能会更新,我看过很多的代码,再次自己实现,就会有很多问题,找不到之类的,建议自己实际再找一遍)。

3b11a14081f01c9960cab0462020731e.png

然后就可以根据自己需要的节点来进行定位,获取数据。

首先要进行的准备工作就是:

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()')

这里就可以得到知乎热榜的问题了。

b06524eb1fc586982f0c5d83e63fda43.png

当然,可以遍历输出,之后的就是字符串操作的范畴了。

附完整代码:

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)

97599694bc567255df2c300c15834fe0.png

有关解析库XPath的学习可以参考我的另一篇文章:XPath解析库的学习。

2019.10.21更新

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

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

另外我将函数进行了封装,阅读性更强。

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

获取网页内容

获取索引

处理结果

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

# -*- 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)

结果展示:

a79c7591fc849a8f8e5ecaefc6ab3aeb.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值