初级爬虫使用指北(4)--解析网页

目录

  1. 目的
  2. 网页构成
  3. 获取标签里的信息
  4. 解析网页的一般流程
  5. 完整代码
  6. 附加题

1. 目的

当获取到指定网页文件(html源代码)后,下一步工作即是要提取出其中所需要的信息。程序的优势在于可以“不知疲倦地”完成某些重复性的工作——这意味着当需求是获取某些具有规律性的重复性的结构化网页时(例如目标网页们都长的差不多),可以让爬虫根据一些 固定规则 抽取网页上的信息。

这一节即是关于如何编写 固定规则 的内容。


2. 网页构成:定位,定位,再定位!

回忆上一节中我获取的网页的数据,我将它打印到屏幕上了,那就像右侧的样子,我想获取的只是这其中很小的一部分信息。

在屏幕中打印网页

Chrome浏览器
所以,我开始利用浏览器的辅助工具帮我在这些数据中找到我需要的信息。
使用Chrome浏览器,在页面上点击右键(Mac触摸板 两只手指按下去),点击“检查”功能。

分析国民级网站-百度一下

“检查”功能
浏览器就会出现“检查”对应的功能板。
现在我想提取百度首页右上角的栏目信息,包括栏目名称和对应的链接(图中左侧的红色方框),这些信息存储在网页对应的标签信息中(图中右侧的红色方框)。

Chrome浏览器-"检查"功能

HTML标签
可以通过以下的标签顺序提取出这些信息,例如,“新闻”。

<body><div id="wrapper"><div id="head"><div class="head_wrapper"><div id="u1"><a href="https....." name="...." class="mnav"> 新闻 </a>

3. 获取标签里的信息:你猜我会怎么提取目标信息

使用爬虫解析网页数据,获取目标信息

"""
上一节中我们是这样做的
data = requests.get("www.baidu.com", headers=headers)
print(data.text)
让我们继续
"""
from bs4 import BeautifulSoup

html =  data.content
soup = BeautifulSoup(html,'lxml')
titles = soup.select("div#wrapper > div#head > div.head_wrapper > div#u1 > a.mnav")
titles[0].get_text
titles[0].get("href")

对比目标信息的标签,有什么发现吗?

<body><div id="wrapper"><div id="head"><div class="head_wrapper"><div id="u1"><a href="https....." name="...." class="mnav"> 新闻 </a>

当然有!

  • 提取 <div id="head"> 使用div#head
  • 提取 <a class="mnav"> 使用 a.mnav

BeautifulSoup是什么?
美丽汤是一个Python用于解析网页的包,记得在命令行中使用pip3 install bs4进行预先安装。

使用美丽汤解析网页后,必须使用soup来命名生成的对象吗?
要是心情不好,我可能就直接s = BeautifulSoup(html,'lxml')


4. 解析网页的一般流程

使用爬虫获取目标信息的过程一般可以包括这些:

  • 使用浏览器“检查”功能定位目标信息(初级爬虫使用指北 (4) 第二节)
  • 使用爬虫获取网页数据(初级爬虫使用指北 (3) )
  • 使用爬虫解析网页数据,获取目标信息(初级爬虫使用指北 (4) 第三节)

5. 完整代码

现在我来完成一次获取网页+解析网页的过程。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 25 13:15:14 2018

@author: alfonso
"""
# ------- obtain html data 指北(3)
import requests
url = 'http://www.baidu.com'
headers = {
    'User-Agent': 'Chrome/53.0.2785.143',
    'Connection': 'keep-alive',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
}
html = requests.get(url, headers=headers)  # 这里我改变了一个变量名称
# ------- mining html 指北(4)
# 1. 导入相关包
from bs4 import BeautifulSoup

# 2. 使用 BeautifulSoup 解析网页
soup = BeautifulSoup(html.content, 'lxml')

# 3. 使用CSS选择器,传入解析规则
titles = soup.select(
    "div#wrapper > div#head > div.head_wrapper > div#u1 > a.mnav")

# 4. 打印出自己所需的信息
print("先看看一共获取到了哪些数据")
print(titles)
print() # 打印一个空行,作用类似于留空一行
print("获取一个标题试试")
print(titles[0].get_text)
print()
print("获取这个标题对应的链接试试")
print(titles[0].get("href"))
print()
运行后的样子

6. 附加题

美丽汤的功能非常强大,如果你真有兴趣的话,可以百度一下它的官方文档(应该有中文版的),或者看看以下我的笔记。
网页源代码

<div class="text">
    <em class="f14 l24">
        <a target="_blank" class="linkto" href="http://news.qq.com/a/20170104/000968.htm">台拟将蔡英文贺岁春联“自自冉冉”一词列入辞典
        </a>
    </em>
</div>

相关BeautifulSoup操作

  • 节点选择器
  • 方法选择器
  • CSS选择器

Let's go

  • 节点选择器
# coding:utf-8
from bs4 import BeautifulSoup
"""
使用 div.text # <div, class="text">
"""
soup = BeautifulSoup(html,'lxml')

news_titles = soup.select("div.text > em.f14 > a.linkto")# 使用select选择器,返回一个列表,包括所有符合的元素
news_titles[0].get_text() # "台拟将蔡英文贺岁春联“自自冉冉”一词列入辞典"
news_titles[0].get("href") # "http://news.qq.com/a/20170104/000968.htm"

'''
a1 > a2 父节点为a1的所属有a2元素
a1#nodeID, 选择 <a1, id="nodeID"> </a1>
a1[nodeID], 选择 <a1, attr="nodeID"> </a1>
其他参见https://cuiqingcai.com/5476.html
'''

## 名称 name
soup.title.name # title 利用name属性获取节点的名称

## 属性 attrs
print(soup.p.attrs) #{'class': ['title'], 'name': 'dromouse'}
print(soup.p.attrs['name']) #dromouse

## 获取内容 string
print(soup.p.string) # 利用string属性获取节点元素包含的文本内容

## 关联
### 子孙节点
soup.p.contents #返回结果是列表形式,得到的结果是直接子节点的列表

soup.p.children # 返回结果是生成器
for i, child in enumerate(soup.p.children): 
    print(i, child)

# contents 和 children 作用相同

# 获得所有子孙节点
soup.p.descendants# 返回结果是生成器
for i, child in enumerate(soup.p.descendants):
    print(i, child)

### 祖先节点
soup.a.parent # 获取直接父节点,生成器类型 
soup.a.parents # 所有祖先节点,生成器类型 
# 用列表输出了它的索引和内容
print(list(enumerate(soup.a.parents)))

### 兄弟节点
print('Next Sibling', soup.a.next_sibling)
print('Prev Sibling', soup.a.previous_sibling)
print('Next Siblings', list(enumerate(soup.a.next_siblings)))
print('Prev Siblings', list(enumerate(soup.a.previous_siblings)))
'''
next_sibling和previous_sibling分别获取节点的下一个和上一个兄弟元素,next_siblings和previous_siblings则分别返回所有前面和后面的兄弟节点的生成器。
'''
  • 方法选择器
## 方法选择器
find_all(name , attrs , recursive , text , **kwargs)
# name = 'ul' 'li' 等标签名称
# attrs = 字典型 {'id': 'list-1'}
# 也可以直接使用一些常见的属性
'''
print(soup.find_all(id='list-1'))
print(soup.find_all(class_='element'))
'''

# text 参数可用来匹配节点的文本,传入的形式可以是字符串,可以是正则表达式对象

print(soup.find_all(text=re.compile('link')))

'''
find相关的方法
find_parents()和find_parent():前者返回所有祖先节点,后者返回直接父节点。
find_next_siblings()和find_next_sibling():前者返回后面所有的兄弟节点,后者返回后面第一个兄弟节点。
find_previous_siblings()和find_previous_sibling():前者返回前面所有的兄弟节点,后者返回前面第一个兄弟节点。
find_all_next()和find_next():前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点。
find_all_previous()和find_previous():前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点。
'''
  • CSS选择器
# 使用CSS选择器
#需要调用select()方法,传入相应的CSS选择器
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))

#节点类型是Tag类型,所以获取属性还可以用原来的方法
for ul in soup.select('ul'):
    print(ul['id'])
    print(ul.attrs['id'])
    print('Get Text:', ul.get_text()) # 效果与.string一样
    print('String:', ul.string) #
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 声明:本文讲解的实战内容,均仅用于学习交流,请勿用于任何商业用途! 一、前言 强烈建议:请在电脑的陪同下,阅读本文...
    Bruce_Szh阅读 12,700评论 6 28
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,474评论 1 45
  • Centos 7启动流程 systemd新特性 核心概念:unit Unit的类型: systemd特性 管理系统...
    JevonWei阅读 441评论 0 0
  • 热闹的新年终于过完啦!体会到了自己心情的起伏跌宕,忍受了孩子最近的任性和拖拉…今天第一天,依然自我察觉。 ...
    等等和姐姐阅读 207评论 0 0
  • 青年们啊,不要再颓废啊,要自强,不要懒惰;要有趣,不要乏味;生活不易且良多趣味,摆脱无病呻吟,人生苦短刹那芳华,...
    寄予路遥阅读 125评论 0 0