大家好!本篇文章主要讲述爬虫一些需要注意的地方、开发环境以及使用正则表达来抓取网站上的信息等。
一、简单介绍
网络爬虫简单的解释就是从网站上获取相关的信息为已所用的一个自动化处理的方式;
1.1 合法性
虽然在2017年就已经开始实施《网络安全法》,但是也没有特别明确爬取公开信息的行为是否违法。
小编搜索了一下资料,自己总结了两点:
- 爬取的数据非盈利使用,只要你没有非常大的获取利润、只要你的采集没有涉及到敏感的信息,一般来说就没有关系
- 爬虫的程序不能使其网站瘫痪,不能一味的追求爬虫的速度,开了大量的线程,导致网站的并发量突增,致其网点奔溃甚至瘫痪,这就比较尴尬了。
1.2 检查robots.txt文件
大家可以查看一下网站的robots.txt的文件,此文件会对爬虫有哪些限制,检查robots.txt文件可以最小化爬虫被封禁的可能,还有可能会发现和网站接口相关的线索;
知乎
csdn网站
开源中国网站
说明:
- User-agent 下的都是表示禁止使用某种代理
- Sitemap 表示网站地图,会提供网站的一些相关的信息,大家可以看一下了解一下
- Crawl-delay 这个表示每次请求之间要间隔的秒数,这个就是网站再提示防止网站服务器过载,还有注意一个/trap链接,用于封禁爬取了不允许链接的恶意爬虫。
并不是所有网站都有robot.txt 文件,大家在爬虫要注意,避免网站服务器过载宕机等风险。
二、开发环境
2.1 Python3.8
大家尽量使用Python3.x版本。
2.2 VSCode开发工具
VSCode环境的搭建看一下之前的推文
大家在使用python的时候会用pip install xxx的指令去安装一些包,会遇到安装不了的情况,我总结了一下解决方案,供大家参考
- 尽量使用管理员打开cmd 或者vscode
- 到python安装路径下安装,如
C:\Users\64385\AppData\Local\Programs\Python\Python38> - 指定国内下载源下载,有很多的资源都是在国外,直接下载的会有网络网速的问题,指定国内的镜像源就会很快,如:
pip install BeautifulSoup4 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
三、正则表达式
3.1 元字符^
如果^元字符放到[]字符集中就是反取的意思
import re
str="python知识学堂,python欢迎你"
result=re.findall('[^python]',str)#反取 匹配除‘python’以外的字符 返回值是list
print(result)
结果:
3.2 元字符*
表示匹配其前面的一个字符0次或多次
import re
str="python知识学堂,欢迎来到学堂"
print(re.findall("知识*",str)) #星号前面的一个字符可以是0次或多次,返回值是list
print(re.findall("学堂*",str)) #星号前面的一个字符可以是0次或多次,返回值是list
结果:
3.3 元字符()
也就是分组匹配,()里面的为一个组或者说是整体
import re
str="python知识学堂,欢迎来到学堂"
print(re.findall("(知识)",str))
print(re.findall("(学堂)",str))
结果:
下面给大家列出常用的,大家自己尝试一下
3.4 常用的元字符
3.5 常用的量词
大家也可以查看 下面网站查看学习
https://docs.python.org/2/howto/regex.html
四、re模块
4.1 re函数参数说明
- pattern:正则模型
- string :要匹配的字符串
- falgs :匹配模式 默认0 re.A (只匹配ASCII字符), re.I (忽略大小写), re.L (语言依赖), re.M (多行模式), re.S (点dot匹配全部字符), re.U (Unicode匹配), and re.X (冗长模式)
4.2 re.findall(pattern,string,flags=0)
对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。
import re
text="python知识学堂,python欢迎你"
print("输入结果:")
print(re.findall(r'[a-z]',text)) #查找所有小写的字母
结果:
4.3 re.search(pattern,string,flags=0)
扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ;注意这和找到一个零长度匹配是不同的。
import re
text="python知识学堂,python欢迎你"
print("输入结果:")
print(re.search(r'[a-z]',text).group()) #只会匹配一个对象
结果:
4.4 re.match(pattern,string,flags=0)
如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。
import re
text="python知识学堂,python欢迎你"
print("输入结果:")
print(re.match(r'[a-z]',text).group()) #只会匹配一个对象
结果:
4.5 flags参数
举例给大家看一下这个参数的使用方式。
import re
text="python知识学堂,PYTHON欢迎你"
print("输入结果:")
print(re.findall('[a-z]',text,re.I)) #获取所有字母不管大小写
结果:
大家可以看到有些地方加了'r' 前缀,在带有 'r' 前缀的字符串字面值中,表示反斜杠不必做任何特殊处理。如 r"\n" 表示包含 '' 和 'n' 两个字符的字符串,而 "\n" 则表示只包含一个换行符的字符串。**建议大家习惯性加前缀'r' **。
这里只举出常用的,还有一些其他的函数,大家可以去网上搜一下资料自行学习一下。下面是官方的网址,可以参考一下
https://docs.python.org/zh-cn/3/library/re.html
下面就使用正则的方式来抓取网站上的信息
五、正则方式抓取
我们会使用到的re(正则表达式)模块 与requests(http)模块,这里我们使用效率更高一点的requests库而并不是urllib库。urllib库的使用方法大家可以百度一下。re模块是python独有的,不需要安装的。requests需要安装,如下
pip install requests
下面会使用正则表达的方法一步一步的教大家怎么去抓取网页的信息。
下面以http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/ 网站为例,抓取当前最新的省份为例。
5.1 F12或右击检查
F12或右击检查查看网站的元素,寻找自己需要信息的位置,并观察,如下图
点击红色箭头的位置,选择网页上的自己所需要的信息,就可以快速定位;
如图可以看到我们所需要的信息的位置以及一些特征,可能这个需要大家知道一点前端上的知识。下面就开始抓取网站上的省份信息。
5.2 第一次抓取
import re
import requests
class demo():
def __init__(self):
try:
response=requests.get("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/")
html=response.text #获取页面的html
print(html)
except:
print('出错了')
if __name__ == '__main__':
demo()
结果:
大家可以看出来页面的信息已经获取到了,但是好像有点乱码。
原因是因为没有设置编码方式
5.3 第二次抓取
import re
import requests
class demo():
def __init__(self):
try:
response=requests.get("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/")
response.encoding='gb2312' #编码转换
html=response.text #获取页面的html
print(html)
except:
print('出错了')
if __name__ == '__main__':
demo()
结果:
可以看到出现了已经把网页上的信息完整的获取到了。
大家考虑一下为啥我这里用了’gb2312’而不是’utf-8’的方式?
这个取决于网站,怎么知道网站是什么编码的?右击查看网页源代码,看下图
圈出来的就是网站的编码方式了。
那么下面就从获取到的网页完整的信息中提取我们需要的信息。
5.4 第三次抓取
要获取到想要的省份信息,先观察省份信息的所在位置的特征。
可以看到省份的信息都是在td 标签内,td标签包含了一个a标签,a标签中包含了下一页的链接地址。我们先只获取省份信息。
import re
import requests
class demo():
def __init__(self):
try:
response=requests.get("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/")
response.encoding='gb2312' #编码转换
html=response.text #获取页面的html
provincelist=re.findall(r"(.*?)
",html)
for p in provincelist:
print(p)
except:
print('出错了')
if __name__ == '__main__':
demo()
结果:
可以获取到所有省份的信息了。
如果还是想要获取二级城市数据,那么我们就要获取a标签中的下级地址,我们还要看一下二级页面我们所要信息的在页面上所在的位置以及特征(与查看省份的一致,不在赘述)。
import re
import requests
import time
class demo():
def __init__(self):
try:
base_url='http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/'
response=requests.get(base_url)
response.encoding='gb2312' #编码转换
html=response.text #获取页面的html
provincelist=re.findall(r"(.*?)
",html)
provinceUrls=re.findall(r".*?
",html)
#for p in provincelist:
# print(p)
for u in provinceUrls:
#print(u)
cityurl=base_url+u
res=requests.get(cityurl)
res.encoding='gb2312' #编码转换
reshtml=res.text #获取页面的html
citylist=re.findall(r"(.*?) ",reshtml)
for c in citylist:
print(c)
time.sleep(0.5)
except:
print('出错了')
if __name__ == '__main__':
demo()
还顺便把二级城市的区域代码也获取到了。大家也要看到了代码里有一个time.sleep的函数,指的是在延迟,单位是秒。因为该网站是没有robots.txt的信息的,所以在爬取信息时需要注意请求间隔时间。
所以仔细观察一下网站的信息特征,不难发现,如果我们一级一级的往下找就会把所有的最新的省市区以及街道的信息都获取到,这样我们就可以很方便的获取到最新的省市区的信息了。大家可以自己尝试一下。
六、总结
爬虫第一篇推文就先介绍到这。本篇主要给大家介绍一下爬虫方面需要注意的地方、使用vscode开发环境的时候会遇到的问题以及使用正则表达式的方式简单的获取省市区。使用正则的方式抓取网页上的信息还是比较简单的,多多练习,希望大家都能爬虫成功。