【莫烦】爬虫基础

正则表达式


正则表达式 (Regular Expression) 又称 RegEx, 是用来匹配字符的一种工具. 在一大串字符中寻找你需要的内容. 它常被用在很多方面, 比如网页爬虫, 文稿整理, 数据筛选等等. 最简单的一个例子, 比如我需要爬取网页中每一页的标题. 而网页中的标题常常是这种形式.

<title>我是标题

而且每个网页的标题各不相同, 我就能使用正则表达式, 用一种简单的匹配方法, 一次性选取出成千上万网页的标题信息. 正则表达式绝对不是一天就能学会和记住的, 因为表达式里面的内容非常多, 强烈建议, 现在这个阶段, 你只需要了解正则里都有些什么, 不用记住, 等到你真正需要用到它的时候, 再反过头来, 好好琢磨琢磨, 那个时候才是你需要训练自己记住这些表达式的时候.

简单的匹配

正则表达式无非就是在做这么一回事. 在文字中找到特定的内容, 比如下面的内容. 我们在 “dog runs to cat” 这句话中寻找是否存在 “cat” 或者 “bird”.

# matching string
pattern1 = "cat"
pattern2 = "bird"
string = "dog runs to cat"
print(pattern1 in string)    # True
print(pattern2 in string)    # False

但是正则表达式绝非不止这样简单的匹配, 它还能做更加高级的内容. 要使用正则表达式, 首先需要调用一个 python 的内置模块re. 然后我们重复上面的步骤, 不过这次使用正则. 可以看出, 如果re.search()找到了结果, 它会返回一个 match 的 object. 如果没有匹配到, 它会返回 None. 这个 re.search()只是 re 中的一个功能, 之后会介绍其它的功能.

import re

# regular expression
pattern1 = "cat"
pattern2 = "bird"
string = "dog runs to cat"
print(re.search(pattern1, string))  # <_sre.SRE_Match object; span=(12, 15), match='cat'>
print(re.search(pattern2, string))  # None

灵活匹配

除了上面的简单匹配, 下面的内容才是正则的核心内容, 使用特殊的 pattern 来灵活匹配需要找的文字.

如果需要找到潜在的多个可能性文字, 我们可以使用[]将可能的字符囊括进来. 比如 [ab]就说明我想要找的字符可以是a 也可以是b. 这里我们还需要注意的是, 建立一个正则的规则, 我们在 pattern 的 “” 前面需要加上一个r用来表示这是正则表达式, 而不是普通字符串. 通过下面这种形式, 如果字符串中出现 “run” 或者是 “ran”, 它都能找到.且返回找到的第一个值

# multiple patterns ("run" or "ran")
ptn = r"r[au]n"       # start with "r" means raw string
print(re.search(ptn, "dog runs to cat"))    # <_sre.SRE_Match object; span=(4, 7), match='run'>

同样, 中括号[]中还可以是以下这些或者是这些的组合. 比如[A-Z]表示的就是所有大写的英文字母. [0-9a-z]表示可以是数字也可以是任何小写字母.

print(re.search(r"r[A-Z]n", "dog runs to cat"))     # None
print(re.search(r"r[a-z]n", "dog runs to cat"))     # <_sre.SRE_Match object; span=(4, 7), match='run'>
print(re.search(r"r[0-9]n", "dog r2ns to cat"))     # <_sre.SRE_Match object; span=(4, 7), match='r2n'>
print(re.search(r"r[0-9a-z]n", "dog runs to cat r1n"))  # <_sre.SRE_Match object; span=(4, 7), match='run'>

按类型匹配

除了自己定义规则, 还有很多匹配的规则时提前就给你定义好了的. 下面有一些特殊的匹配类型给大家先总结一下, 然后再上一些例子.

  • \d : 任何数字
  • \D : 不是数字
  • \s : 任何 white space, 如 [\t\n\r\f\v]
  • \S : 不是 white space
  • \w : 任何大小写字母, 数字和 “” [a-zA-Z0-9]
  • \W : 不是 \w
  • \b : 空白字符 (只在某个字的开头或结尾)
  • \B : 空白字符 (不在某个字的开头或结尾)
  • \ : 匹配 \
  • . : 匹配任何字符 (除了 \n)
  • ^ : 匹配开头
  • $ : 匹配结尾
  • ? : 前面的字符可有可无
    下面就是具体的举例说明啦.
# \d : decimal digit
print(re.search(r"r\dn", "run r4n"))           # <_sre.SRE_Match object; span=(4, 7), match='r4n'>
# \D : any non-decimal digit
print(re.search(r"r\Dn", "run r4n"))           # <_sre.SRE_Match object; span=(0, 3), match='run'>
# \s : any white space [\t\n\r\f\v]
print(re.search(r"r\sn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(0, 3), match='r\nn'>
# \S : opposite to \s, any non-white space
print(re.search(r"r\Sn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(4, 7), match='r4n'>
# \w : [a-zA-Z0-9_]
print(re.search(r"r\wn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(4, 7), match='r4n'>
# \W : opposite to \w
print(re.search(r"r\Wn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(0, 3), match='r\nn'>
# \b : empty string (only at the start or end of the word)
print(re.search(r"\bruns\b", "dog runs to cat"))    # <_sre.SRE_Match object; span=(4, 8), match='runs'>
# \B : empty string (but not at the start or end of a word)
print(re.search(r"\B runs \B", "dog   runs  to cat"))  # <_sre.SRE_Match object; span=(8, 14), match=' runs '>
# \\ : match \
print(re.search(r"runs\\", "runs\ to me"))     # <_sre.SRE_Match object; span=(0, 5), match='runs\\'>
# . : match anything (except \n)
print(re.search(r"r.n", "r[ns to me"))         # <_sre.SRE_Match object; span=(0, 3), match='r[n'>
# ^ : match line beginning
print(re.search(r"^dog", "dog runs to cat"))   # <_sre.SRE_Match object; span=(0, 3), match='dog'>
# $ : match line ending
print(re.search(r"cat$", "dog runs to cat"))   # <_sre.SRE_Match object; span=(12, 15), match='cat'>
# ? : may or may not occur
print(re.search(r"Mon(day)?", "Monday"))       # <_sre.SRE_Match object; span=(0, 6), match='Monday'>
print(re.search(r"Mon(day)?", "Mon"))          # <_sre.SRE_Match object; span=(0, 3), match='Mon'>

如果一个字符串有很多行, 我们想使用 ^ 形式来匹配行开头的字符, 如果用通常的形式是不成功的. 比如下面的 “I” 出现在第二行开头, 但是使用r"^I"却匹配不到第二行, 这时候, 我们要使用 另外一个参数, 让re.search()可以对每一行单独处理. 这个参数就是flags=re.M, 或者这样写也行 flags=re.MULTILINE.

string = """
dog runs to cat.
I run to dog.
"""
print(re.search(r"^I", string))                 # None
print(re.search(r"^I", string, flags=re.M))     # <_sre.SRE_Match object; span=(18, 19), match='I'>

重复匹配

如果我们想让某个规律被重复使用, 在正则里面也是可以实现的, 而且实现的方式还有很多. 具体可以分为这三种:

  • \*: 重复零次或多次
    -\+ : 重复一次或多次
  • {n, m}: 重复 n 至 m 次
  • {n} : 重复 n 次
    举例如下:
# * : occur 0 or more times
print(re.search(r"ab*", "a"))             # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.search(r"ab*", "abbbbb"))        # <_sre.SRE_Match object; span=(0, 6), match='abbbbb'>

# + : occur 1 or more times
print(re.search(r"ab+", "a"))             # None
print(re.search(r"ab+", "abbbbb"))        # <_sre.SRE_Match object; span=(0, 6), match='abbbbb'>

# {n, m} : occur n to m times
print(re.search(r"ab{2,10}", "a"))        # None
print(re.search(r"ab{2,10}", "abbbbb"))   # <_sre.SRE_Match object; span=(0, 6), match='abbbbb'>

分组

我们甚至可以为找到的内容分组, 使用 () 能轻松实现这件事. 通过分组, 我们能轻松定位所找到的内容. 比如在这个(\d+)组里, 需要找到的是一些数字, 在 (.+)这个组里, 我们会找到 “Date: “ 后面的所有内容. 当使用 match.group()时, 他会返回所有组里的内容, 而如果给 .group(2) 里加一个数, 它就能定位你需要返回哪个组里的信息.

match = re.search(r"(\d+), Dat (e:.+)", "ID: 021523, Date: Feb/12/2017")
print(match.group())                   # 021523, Date: Feb/12/2017
print(match.group(1))                  # 021523
print(match.group(2))                  # e: Feb/12/2017

有时候, 组会很多, 光用数字可能比较难找到自己想要的组, 这时候, 如果有一个名字当做索引, 会是一件很容易的事. 我们字需要在括号的开头写上这样的形式 ?P<名字> 就给这个组定义了一个名字. 然后就能用这个名字找到这个组的内容.

match = re.search(r"(?P\d+), Date: (?P.+)", "ID: 021523, Date: Feb/12/2017")
print(match.group('id'))                # 021523
print(match.group('date'))              # Date: Feb/12/2017

findall

前面我们说的都是只找到了最开始匹配上的一项而已, 如果需要找到全部的匹配项, 我们可以使用findall功能. 然后返回一个列表. 注意下面还有一个新的知识点, |是 or 的意思, 要不是前者要不是后者.

# findall
import re
print(re.findall(r"r(ua)n", "run ran ruan ren")) #['ua']
print(re.findall(r"(ua)", "run ran eua ruan ren")) #['ua', 'ua']
print(re.findall(r"r[ua]n", "run ran ruan ren")) #['run', 'ran']
# | : or
print(re.findall(r"r[u|a]n", "run ran ruan ren")) #['run', 'ran']
print(re.findall(r"r(u|a)n", "run ran ruan ren"))    # ['run', 'ran']

replace

我们还能通过正则表达式匹配上一些形式的字符串然后再替代掉这些字符串. 使用这种匹配 re.sub(), 将会比 python 自带的 string.replace() 要灵活多变.

print(re.sub(r"r[au]ns", "catches", "dog runs to cat"))     # dog catches to cat

split

再来我们 Python 中有个字符串的分割功能, 比如想获取一句话中所有的单词. 比如 "a is b".split(" "), 这样它就会产生一个列表来保存所有单词. 但是在正则中, 这种普通的分割也可以做的淋漓精致.

import re
print(re.split(r"[;\.]", "ac.d;e"))#['ac', 'd', 'e']
print(re.split(r"[.]", "ac.d;e"))#['ac', 'd;e']
print(re.split(r"[\.]", "ac.d;e"))#['ac', 'd;e']
print(re.split(r"(\.)", "ac.d;e"))#['ac', '.', 'd;e']
print(re.split(r"(.)", "ac.d;e"))#['', 'a', '', 'c', '', '.', '', 'd', '', ';', '', 'e', '']

compile

最后, 我们还能使用 compile 过后的正则, 来对这个正则重复使用. 先将正则 compile 进一个变量, 比如 compiled_re, 然后直接使用这个 compiled_re来搜索.

compiled_re = re.compile(r"r[ua]n")
print(compiled_re.search("dog ran to cat"))  # <_sre.SRE_Match object; span=(4, 7), match='ran'>

小抄

为了大家方便记忆, 我很久以前在网上找到了一份小抄, 这个小抄的原出处应该是这里. 小抄很有用, 不记得的时候回头方便看.
【莫烦】爬虫基础_第1张图片

爬虫简介


why?

其实你身边到处都是爬虫的产物, 比如说搜索引擎 (Google, 百度), 他们能为你提供这么多搜索结果, 也都是因为它们爬了很多信息, 然后展示给你. 再来说一些商业爬虫, 比如爬爬淘宝的同类商品的价格信息, 好为自己的商品挑选合适的价格. 爬虫的用途很多很多, 如果你搞机器学习, 爬虫就是你获取数据的一种途径, 网上的信息成百上千, 只要你懂爬虫, 你都能轻松获取.

我做过的一些有趣的爬虫

(https://morvanzhou.github.io/tutorials/data-manipulation/scraping/1-00-why/)

为什么做这个教程 (其他教程推荐)

这个教程提供了你一次入门的机会, 当然网上还有很多很好的入门教程, 比如:

崔庆才 的Python爬虫学习系列教程
知乎问答中的各种推荐
孔淼 的一看就明白的爬虫入门讲解
这些都是非常好的参考资料, 你的学习请不要只限于一个网站. 因为像机器学习一样, 爬虫也囊括的东西绝非不止一点点. 而你为什么要看看我的爬虫教程呢? 因为我只关注基础, 我认为入门是最重要的, 能帮你成功引上路子, 我想你会轻松很多. 而且搭配视频讲解的形式, 也会更加容易理解. 是为初学者定制的. 如果你已经入过门, 想着如何商业化爬虫, 这个教程应该不能满足你的需求了.

当我第一次接触爬虫的时候, 其实很陌生, 完全不知道从何开始. 在网上自己搜一些介绍, 但是他们的介绍都太笼统了, 给你丢几个关键词, 让你自己解决. 当时我就懵逼了, 看着那些关键词 (requests, urllib, beautifulsoup, scrapy) 不知道从何下手, 我估计你也会有这种感觉. 当时, 我花了大把的精力, 想弄懂这些东西和爬虫的关系. 而且分清如果只想入门, 我们需要掌握哪些? 毕竟商业化和入门还是有很大不同的. 有些关键词或者模块是为了商业化而用的. 所以我花了很多时间, 整理网上的这些信息. 总结出一条入门爬虫的便捷之路.

课程介绍

这系列教程按照上面的逻辑来教会你爬虫, 我们会从网页的基本结构开始讲述, 慢慢使用一些简单的工具, 做一些简单的爬虫. 还会有一些小练习, 让你爬爬真正的互联网. 下载美图, 逛逛百度百科, 全网爬取等等. 当你懂得了爬虫的概念, 我们在深入一些, 谈谈如何加速你那和蠕虫(爬的慢)一样的爬虫, 把它升级为一只小飞虫(多进程,异步爬取). 当然这些内容都不会特别深入, 重点是把你带入门. 但是我会在每节内容里加一些链接, 提供给想要深入了解的朋友们.

了解网页结构

学习爬虫, 首先要懂的是网页. 支撑起各种光鲜亮丽的网页的不是别的, 全都是一些代码. 这种代码我们称之为 HTML, HTML 是一种浏览器(Chrome, Safari, IE, Firefox等)看得懂的语言, 浏览器能将这种语言转换成我们用肉眼看到的网页. 所以 HTML 里面必定存在着很多规律, 我们的爬虫就能按照这样的规律来爬取你需要的信息.

其实除了 HTML, 一同构建多彩/多功能网页的组件还有 CSSJavaScript. 但是这个简单的爬虫教程, 大部分时间会将会使用 HTML. CSS 和 JavaScript 会在后期简单介绍一下. 因为爬网页的时候多多少少还是要和 CSS JavaScript 打交道的.

虽然莫烦Python主打的是机器学习的教程. 但是这个爬虫教程适用于任何想学爬虫的朋友们. 从机器学习的角度看, 机器学习中的大量数据, 也是可以从这些网页中来, 使用爬虫来爬取各种网页上面的信息, 然后再放入各种机器学习的方法, 这样的应用途径正在越来越多被采用. 所以如果你的数据也是分散在各个网页中, 爬虫是你减少人力劳动的必修课.

网页基本组成部分

在真正进入爬虫之前, 我们先来做一下热身运动, 弄明白网页的基础, HTML 有哪些组成部分, 是怎么样运作的. 如果你已经非常熟悉网页的构造了, 欢迎直接跳过这一节, 进入下面的学习.

我制作了一个非常简易的网页, 给大家呈现以下最骨感的 HTML 结构. 如果你点开它, 呈现在你眼前的, 就是下面这张图的上半部分. 而下半部分就是我们网页背后的 HTML code.
【莫烦】爬虫基础_第2张图片

如何看到 HTML 的 source code
在你的浏览器中 (我用的是 Google Chrome), 显示网页的地方, 点击鼠标右键, 大多数浏览器都会有类似这样一个选项 “View Page Source”或查看网页源代码. 点击它就能看到页面的源码了.
【莫烦】爬虫基础_第3张图片
在 HTML 中, 基本上所有的实体内容, 都会有个 tag (…)来框住它. 而这个被 tag 住的内容, 就可以被展示成不同的形式, 或有不同的功能. 主体的 tag 分成两部分, headerbody. 在 header 中, 存放这一些网页的网页的元信息, 比如说 title, 这些信息是不会被显示到你看到的网页中的. 这些信息大多数时候是给浏览器看, 或者是给搜索引擎的爬虫看.

<head>
	<meta charset="UTF-8">
	<title>Scraping tutorial 1 | 莫烦Pythontitle>
	<link rel="icon" href="https://morvanzhou.github.io/static/img/description/tab_icon.png">
head>

HTML 的第二大块是body, 这个部分才是你看到的网页信息. 网页中的 heading, 视频, 图片和文字等都存放在这里. 这里的

tag 就是主标题, 我们看到呈现出来的效果就是大一号的文字.

里面的文字就是一个段落. 里面都是一些链接. 所以很多情况, 东西都是放在这些 tag 中的.

<body>
    <h1>爬虫测试1h1>
    <p>
        这是一个在 <a href="https://morvanzhou.github.io/">莫烦Pythona>
        <a href="https://morvanzhou.github.io/tutorials/scraping">爬虫教程a> 中的简单测试.
    p>
body>

爬虫想要做的就是根据这些 tag 来找到合适的信息.

用 Python 登录网页

好了, 对网页结构和 HTML 有了一些基本认识以后, 我们就能用 Python 来爬取这个网页的一些基本信息. 首先要做的, 是使用 Python 来登录这个网页, 并打印出这个网页 HTML 的 source code. 注意, 因为网页中存在中文, 为了正常显示中文, read() 完以后, 我们要对读出来的文字进行转换, decode()成可以正常显示中文的形式.

from urllib.request import urlopen

# if has Chinese, apply decode()
html = urlopen(
    "https://morvanzhou.github.io/static/scraping/basic-structure.html"
).read().decode('utf-8')
print(html)

print 出来就是下面这样啦. 这就证明了我们能够成功读取这个网页的所有信息了. 但我们还没有对网页的信息进行汇总和利用. 我们发现, 想要提取一些形式的信息, 合理的利用 tag 的名字十分重要.


<html lang="cn">
<head>
	<meta charset="UTF-8">
	<title>Scraping tutorial 1 | 莫烦Pythontitle>
	<link rel="icon" href="https://morvanzhou.github.io/static/img/description/tab_icon.png">
head>
<body>
	<h1>爬虫测试1h1>
	<p>
		这是一个在 <a href="https://morvanzhou.github.io/">莫烦Pythona>
		<a href="https://morvanzhou.github.io/tutorials/scraping">爬虫教程a> 中的简单测试.
	p>

body>
html>

【莫烦】爬虫基础_第4张图片

匹配网页内容

所以这里我们使用 Python 的正则表达式 RegEx 进行匹配文字,如果是初级的网页匹配, 我们使用正则完全就可以了, 高级一点或者比较繁琐的匹配, 我还是推荐使用 BeautifulSoup.

如果我们想用代码找到这个网页的 title, 我们就能这样写. 选好要使用的 tag 名称</code>. 使用正则匹配.</p> <pre><code class="prism language-py"><span class="token keyword">import</span> re res <span class="token operator">=</span> re<span class="token punctuation">.</span>findall<span class="token punctuation">(</span>r<span class="token string">"<title>(.+?)", html) print("\nPage title is: ", res[0]) # Page title is: Scraping tutorial 1 | 莫烦Python

如果想要找到中间的那个段落

, 我们使用下面方法, 因为这个段落在 HTML 中还夹杂着 tab, new line, 所以我们给一个flags=re.DOTALL 来对这些 tab, new line 不敏感,以选择多行的内容.

res = re.findall(r"

(.*?)

"
, html, flags=re.DOTALL) # re.DOTALL if multi line print("\nPage paragraph is: ", res[0]) # Page paragraph is: # 这是一个在 莫烦Python # 爬虫教程 中的简单测试.

最后一个练习是找一找所有的链接, 这个比较有用, 有时候你想找到网页里的链接, 然后下载一些内容到电脑里, 就靠这样的途径了.

res = re.findall(r'href="(.*?)"', html)
print("\nAll links: ", res)
# All links:
['https://morvanzhou.github.io/static/img/description/tab_icon.png',
'https://morvanzhou.github.io/',
'https://morvanzhou.github.io/tutorials/scraping']

注:

  • (.+)默认是贪婪匹配 贪婪匹配是先看整个字符串是否匹配,如果不匹配,它会去掉字符串的最后一个字符,并再次尝试。如果还不匹配,那么再去掉当前最后一个,直到发现匹配或不剩任何字符。
  • (.+?)为惰性匹配 惰性匹配是从左侧第一个字符开始向右匹配, 先看第一个字符是不是一个匹配, 如果不匹配就加入下一个字符再尝式匹配, 直到发现匹配

BeautifulSoup 解析网页


BeautifulSoup 解析网页:基础

找到需要的信息时, BeautifulSoup 就是一个找信息好帮手. 它能帮你又快有准地找到信息. 大大简化了使用难度.
本节学习代码
BeautifulSoup 英文官网, 中文官网
本节使用的爬虫测试网页

我们总结一下爬网页的流程, 让你对 BeautifulSoup 有一个更好的定位.

  1. 选着要爬的网址 (url)
  2. 使用 python 登录上这个网址 (urlopen等)
  3. 读取网页信息 (read() 出来)读取网页信息 (read() 出来)
  4. 将读取的信息放入 BeautifulSoup
  5. 使用 BeautifulSoup 选取 tag 信息等 (代替正则表达式)

初学的时候总是搞不懂这些包是干什么的, 现在你就能理解这个 BeautifulSoup 到底是干什么的了.

安装

等什么, 知道 BeautifulSoup 这么方便, 我们就赶紧装一个吧. 安装的步骤很简单, 用 pip 就能轻松安装.

# Python 2+
pip install beautifulsoup4

# Python 3+
pip3 install beautifulsoup4

注意在名字后面还有个 “4”, 可能是代表第4版吧. 如果你在安装的时候遇到任何问题, 请参考他们官网上的解决方案.

简单实用方法

这次我们还是爬一爬上次爬的那个基本网页. BeautifulSoup 使用起来非常简单, 我们先按常规读取网页.

from bs4 import BeautifulSoup
from urllib.request import urlopen

# if has Chinese, apply decode()
html = urlopen("https://morvanzhou.github.io/static/scraping/basic-structure.html").read().decode('utf-8')
print(html)

回顾一下, 每张网页中, 都有两大块, 一个是 , 一个是 , 我们等会用 BeautifulSoup 来找到 body 中的段落

和所有链接.


<html lang="cn">
<head>
	<meta charset="UTF-8">
	<title>Scraping tutorial 1 | 莫烦Pythontitle>
	<link rel="icon" href="https://morvanzhou.github.io/static/img/description/tab_icon.png">
head>
<body>
	<h1>爬虫测试1h1>
	<p>
		这是一个在 <a href="https://morvanzhou.github.io/">莫烦Pythona>
		<a href="https://morvanzhou.github.io/tutorials/scraping">爬虫教程a> 中的简单测试.
	p>

body>
html>

读取这个网页信息, 我们将要加载进 BeautifulSoup, 以 lxml的这种形式加载. 除了 lxml, 其实还有很多形式的解析器, 不过大家都推荐使用 lxml 的形式. 然后 soup 里面就有着这个 HTML 的所有信息. 如果你要输出

标题, 可以就直接 soup.h1.

若无法使用lxml可替换为html.parser,或安装lxml

soup = BeautifulSoup(html, features='lxml')
print(soup.h1)

"""

爬虫测试1

"""
print('\n', soup.p) """

这是一个在 莫烦Python 爬虫教程 中的简单测试.

"""

如果网页中有过个同样的 tag, 比如链接 , 我们可以使用find_all() 来找到所有的选项. 因为我们真正的 link 不是在中间 , 而是在里面, 也可以看做是 的一个属性. 我们能用像 Python 字典的形式, 用 key 来读取l["href"].

all_href = soup.find_all('a')
"""
爬虫教程
"""

all_href = soup.find_all('a')
all_href = [l['href'] for l in all_href]
print('\n', all_href)

# ['https://morvanzhou.github.io/', 'https://morvanzhou.github.io/tutorials/scraping']

懂得这些还是远远不够的, 真实情况往往比这些复杂. BeautifulSoup 还有很多其他的选择”增强器”. 下次, 我们来了解一些 CSS 的概念, 用 BeautifulSoup 加上 CSS 来选择内容.

BeautifulSoup 解析网页:CSS

  • CSS 的详细规则

什么是 CSS

提到这个, 我们肯定需要知道什么是 CSS. HTML 和 CSS 是一对好搭档, 他们共同组成了当今的众多网页. 如果这个世界上没有 CSS, 你看到的所有网页可能都长得像这样. 特别”骨感”!

如果有 CSS, 你的网页就变得丰富多彩起来. 文字有了颜色, 字体, 位置也多样了, 图片也有规则了.

所以, CSS 主要用途就是装饰你 “骨感” HTML 页面. 如果将 HTML 比喻成没穿衣服的人, 那 CSS 就是五颜六色的衣服. 穿在人身上让人有了气质. CSS 的规则很多, 好在如果你只是需要爬网页, 你并不需要学习 CSS 的这些用法或规则, (如果你想, 你可以看到这里), 你只需要注意 CSS 的一条规则就能玩转爬虫了.

CSS 的 Class

这条规则就是 CSS 的 Class, CSS 在装饰每一个网页部件的时候, 都会给它一个名字. 而且一个类型的部件, 名字都可以一样. 比如我们这个练习网页. 里面的字体/背景颜色, 字体大小, 都是由 CSS 来掌控的.
【莫烦】爬虫基础_第5张图片
而 CSS 的代码, 可能就会放在这个网页的 中. 我们先使用 Python 读取这个页面.

from bs4 import BeautifulSoup
from urllib.request import urlopen

# if has Chinese, apply decode()
html = urlopen("https://morvanzhou.github.io/static/scraping/list.html").read().decode('utf-8')
print(html)

中, 你会发现有这样一些东西被放在