先了解网站,
例如,https://morvanzhou.github.io/static/scraping/basic-structure.html
右击查看元素,其实就是source code
在HTML中,基本所有实体内容,都会有一个tag来框住他,而这个被tag住的东西,就可以展示成不同的形式,或者有不同的功能,
主体的tag分成两部分
,header和body.在header中,存放一些网页的元信息,比如tittle.这些信息我们看不到,而是给i浏览器看的,或者给搜索引擎的爬虫看的.
HTML第二大块是body,这个部分才是我看到的网页信息,网页中的heading.
视频,图片,和文字等都存放在这里
tag就算主标题,我们看到的呈现出来的效果就是大一号的亮眼的文字.
里面的文字就是一个段落. 里面都是一些链接, **所以大部分情况,东西都是存放在这些tag中的**
<body>
<h1>爬虫测试1</h1>
<p>
这是一个在 <a href="https://morvanzhou.github.io/">莫烦Python</a>
<a href="https://morvanzhou.github.io/tutorials/scraping">爬虫教程</a> 中的简单测试.
</p>
</body>
爬虫要做的就是根据这些tag来找到合适的信息.
用Python登陆网页
先用python来爬取这个网页的一些基本信息,首先要做的就是python来登陆这个网页,并且打印出这个网页HTML的source code.
**注意因为网页中存在中文,为了正常显示中文,read()完以后.我们要对读出来的文字进行转换,否则就是一堆看不懂的乱码,**
**decode()则可以正常显示中文的形式**
from urllib.request import urlopen
#如果有中文 则在后面.decode('utf-8')
html = urlopen(
"https://morvanzhou.github.io/static/scraping/basic-structure.html"
).read().decode('utf-8')
#然后打印
print(html)
结果就是这样咯,说明我成功读取到了这个网页的所有信息,然而我们还没有对他充分利用,
即利用某些方法把里面的东西提炼出来
当我们想要提取某类网页中的某种信息,合理利用tag的名字则十分重要
匹配网页内容
个人认为python掌握正则表达式RegEx是一件很重要的事情,当然也会给我们带来不小的麻烦.
要肯花时间,闷头学下去,必有所成.
先用beautiful soup找一下网页的title
res = re.findall(r"<title>(.+?)</title>",html)
print("\nPage title is:", res[0])
有必要解释下
- res = re.findall()是抓取所有以符合括号正则表达式含义的内容
- re模块就是正则表达式模块
普通字符 | 匹配自身 |
---|---|
. | 匹配任意除换行符"\n"外的字符 |
|转义字符,使后一字符变成其他意思如\n |
好吧,我们来简单学习一下python中的正则表达式,
入门还是不难的,但是如果忽略这些基础知识,总会觉得心里很舒服
== 来自菜鸟教程==
有个地方注意,python的print在版本2.0不需要括号,3.0需要括号,有些教程比较老,注意区分一下
span() 返回一个元组包含匹配 (开始,结束) 的位置
import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print ("matchObj.group() : ", matchObj.group())
print ("matchObj.group(1) : ", matchObj.group(1))
print ("matchObj.group(2) : ", matchObj.group(2))
else:
print ("No match!!")
知识题要
- 首先** r’(.) are (.?) .*’**这是一个字符串,前面一个r表示字符串为非转义的原始字符串,让编译器忽略反斜杠,即忽略转移字符.但是如果这个字符串里没有反斜杠,则这个r可有可无
- **(.*)**第一个匹配分组,*代表匹配除换行符之外的所有字符
- **(.?)**第二个匹配分组,.?后面多了一个问号,代表非贪婪模式,也就是说匹配到为止
- 后面的一个.没有括号包围,所以不是分组.匹配效果和第一个一样,但是不计入匹配结果中.
matchObj.group()等同于matchObj.group(0),表示匹配到的完整文本字符
matchObj.group(1)得到第一组匹配结果,也就是(.)匹配到的
matchObj.group(2)得到第二组匹配结果,也就是(.*?)匹配到的
re.M表示多行模式,re.I表示忽略大小写
re.X忽略空格和#后面的注释
匹配结果只有两组,所以如果填3会报错
import re
匹配零个或多个字符
\d*表示0~9的某位数字开头
1表示1到9的数字开头
$表示以什么结束
/2\d*$/表示以1到9开头,0~9数字结尾的字符串
以下为简写, \d*2 表示以数字开头,以2结尾
a = 'c45java452c#1431254 Python|Javascript'
r = re.findall("\d*2", a);
r
[‘452’, ‘14312’]
import re
匹配零个或多个字符 \d表示0~9的某位数字开头 ^[1-9]表示1到9的数字开头 表示以什么结束/[1−9]\d∗表示以什么结束/[1−9]\d∗/表示以1到9开头,0~9数字结尾的字符串 以下为简写, \d2 表示以数字开头,以2结尾
*匹配零个或多个
零个的意思是符号后面的字符数 零个或多个
a = 'c45java452c#1431254 Python|Javascript'
r = re.findall("\d*2", a);
print(r)
['452', '14312']
+号是匹配一个或多个字符
\d+表示匹配多个数字字符
r = re.findall("\d+9", a)
r
[]
## 使用.匹配
.代表任意字符
r = re.findall("\d+....", a);
r
['45java', '452c#14', '31254 Pyt']
.? .是匹配任意字符的,
r = re.findall(".*", a)
r
['c45java452c#1431254 Python|Javascript', '']
r = re.findall(".*J", a)
r
['c45java452c#1431254 Python|J']
### f非贪婪匹配. ?
r = re.findall(".*?1", a)
r
['c45java452c#1', '431']
r = re.findall(".*1", a)
r #到最后一个1 才结束
['c45java452c#1431']
字符集[]
r = re.findall("[12]", a)
r
['2', '1', '1', '2']
自动识别成字符集
r = re.findall("[12][125]", a)
r
['12']
r = re.findall("\d", a)
r
['4', '5', '4', '5', '2', '1', '4', '3', '1', '2', '5', '4']
r = re.findall("[234]", a)
r
['4', '4', '2', '4', '3', '2', '4']
+号匹配一个或多个字符
r = re.findall("[234]+", a)
r
['4', '4', '2', '43', '2', '4']
r = re.findall("[a-z]+", a)
r
['c', 'java', 'c', 'ython', 'avascript']
r = re.findall("[a-zA-Z]+", a)
r
['c45java452c', '1431254', 'Python', 'Javascript']
r = re.findall("[a-zA-Z\d]+", a)
print(a)
r
c45java452c#1431254 Python|Javascript
['c45java452c', '1431254', 'Python', 'Javascript']
数量词
r = re.findall("[a-zA-Z]+", a)
print(a)
r
c45java452c#1431254 Python|Javascript
['c', 'java', 'c', 'Python', 'Javascript']