一般来说当我们爬取网页的整个源代码后,是需要对网页进行解析的。

正常的解析方法有三种

①:正则匹配解析

②:BeatuifulSoup解析

③:lxml解析


正则匹配解析:

在之前的学习中,我们学习过爬虫的基本用法,比如/s,/d,/w,*,+,?等用法,但是在对爬取到的网页进行解析的时候,仅仅会这些基础的用法,是不够用的,因此我们需要了解Python中正则匹配的经典函数。

re.match:

runoob解释:re.match尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match就会返回none,如果匹配成功,re.match就会返回一个匹配的对象,否则也为null.查看匹配返回的对象要使用group函数的方法。

语法:

re.match(pattern,string,flags=0)

解释:pattern是匹配的正则表达式,string是所要匹配的字符,而flags是标志位,用于匹配区分是否大小写,多行匹配等。具体用法如下列表格:

修饰符 描述
re.I 使得匹配对大小写不敏感
re.M 多行匹配,影响^和$
re.S 使得.匹配包括换行在内的所有字符(正常情况下.不匹配换行符,这个行为很危险,容易被黑客利用绕过)
re.U 根据Unicode字符集解析字符,这个标志影响\w,\W,\b,\B

代码案例:

#!/usr/bin/python
#coding:utf-8
import re
line="Anyone who dreams there gets"
match=re.match(r'(.*) dreams (.*?).*',line,re.M|re.I)
#match1=re.match(r'(.*) Dreams (.*?)',line,re.M)#大小写敏感,匹配会失败
match2=re.match(r'(.*) Dreams (.*?).*',line,re.M|re.I)#非贪婪模式
match3=re.match(r'(.*) Dreams (.*).*',line, re.M|re.I)#贪婪模式
print(match.group())
#print(match1.group())
print(match2.group())
print("match 0:",match.group(0))#Anyone who dreams there gets
print("match 1:",match.group(1))#Anyone who
print("match 2:",match.group(2))#' '
print("match2 0:",match2.group(0))#Anyone who dreams there gets
print("match2 1:",match2.group(1))#Anyone who
print("match2 2:",match2.group(2))#' '
print("match3 0:",match3.group(0))#Anyone who dreams there gets
print("match3 1:",match3.group(1))#Anyone who
print("match3 2:",match3.group(2))#there gets

可以看到(.*?)非贪婪模式会匹配空格,并且放入group(2),默认group()==group(0)位匹配的整句话,而groups()函数会把匹配的结果放到一个列表里。对匹配返回的结果比如match,我们可以使用start(),end(),span(),来查看开始,结束的位置。

正则匹配字符串r'(.*)'的r代表raw string,代表匹配纯粹的字符串,使用它就不会对反引号里的反斜杠进行特殊处理,比如换行符\n不会进行转义。因此我们可以了解下正则匹配中的转义:

在不加r的前提下'\\\\'会被转义,这是因为字符串经过了两次转移,一次是字符串转义,转义成为了'\\',然后进行了正则转义。

如果加了r就会变成'\\',因为以纯粹的字符串进行匹配取消了字符串转义。这就是正则匹配中的转义流程。


re.search

re.search与re.match不同之处在于re.search会扫描整个字符串,并且返回第一个结果,此外re.match并无太大差别,同样可以使用m.span(),m.start(),m.end()来查看起始位置等等

re.findall

在之前的一篇博文:https://www.cnblogs.com/Tianwenfeigong/p/14397771.html

使用到过re.findall函数,用以对bilibili中上传Python教程的Up主进行爬取,从那篇博文中,我们可以看出,re.findall返回的是列表,,对他的数据提取一般先用set()转换为集合的方式会更佳。

在那篇博文中,我还不懂对href进行包含但不选择,因此正则匹配的内容有限,导致正则匹配适用的环境并不多,因此重新爬取新的内容,并且引入一个新的小技巧;

目标:爬取第一个bilibili搜索栏所有的python视频的标题

代码:

#!/usr/bin/python
#coding=utf-8
import requests
import re
link="https://search.bilibili.com/all?keyword=python&from_source=nav_search&spm_id_from=333.851.b_696e7465726e6174696f6e616c486561646572.9"
headers={"User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0'}
r=requests.get(link,headers=headers)
text=r.text
title_list=re.findall('<a title=(.*?) href=.*?>',text)
for i in title_list:
print(i)

重点内容:title_list=re.findall('<a title=(.*?) href=.*?>',text)

第二个.?表示匹配满足条件的结果,第一个(.?)表示对满足条件的结果进行提取

通过这个方式我们就可以提取标题了

BeautifulSoup解析

BeautifulSoup可以从HTML或者XML中提取数据,类似一个工具箱,使用BeautifulSoup时,可以使用一些解析器使得速度快一点呢,目前比较好的的Lxml HTML解析器,使用方法如下:

soup=BeautifulSoup(r.text,"lxml")

BeautifulSoup的本质是复杂的树形结构,对他的对象提取一般有三种方法:

①:遍历文档树,遍历文档树类似于Linux的文件目录,既然是树形结构一定是从上到下的所以第一个节点一定是header,具体方法如下:

#如要获得以<h1>开头的标签,则可以使用
soup.header.h1
#会返回类似于<h1 id="name">CuLin</h1>的内容
#如果要获得div的所有子节点,则可以使用
soup.header.div.contents
#如果要获得div的所有孩子节点,则可以使用
soup.header.div.children
#如果要获得div的子子孙孙节点,则可以使用
soup.header.div.descendants
#如果要获得节点a的父节点,则可以使用
soup.header.div.a.parents

②:搜索文档树:

遍历文档树的局限性很大,一般不是很推荐使用,更多的还是搜索文档树。使用方法很便捷,精髓在find和find_all函数,比如我们要爬取博客文章的标题:

#!/usr/bin/python
#coding:utf-8
import requestss
from bs4 import BeautifulSoup
link="http://www.santostang.com/"
r=requests.get(link)
soup=BeautifulSoup(r.text,"lxml")
#打印第一篇标题
first_title=soup.find("h1",class_="post-title").a.text.strip()
#打印所有文章的
all_title=soup.find_all("h1",class_="post-title")
for i in range(len(all_titile)):
print("No ",i," is ",all_title[i].a.text.strip())

③: CSS选择器:

Css可以作为遍历文档树鼩提取数据,也可以按照搜索文档树的方法去搜索,但是我个人觉得css选择器不如selenium好用,并且使用上很不方便,所以不再赘述

此外lxml解析器重点是xpath,这在selenium也有很好的体现,而xpath的选择我们可以在网页检查中直接检查xpath更为方便。

项目实战

爬取贝壳网站南京房源信息,总房价,平均房价,地点

#coding:utf-8
import requests
import re
from bs4 import BeautifulSoup
link="https://nj.ke.com/ershoufang/pg"
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0","Host":
"nj.ke.com"}
for i in range(1,20):
link_=link+str(i)+'/'
r=requests.get(link_,headers=headers)
soup=BeautifulSoup(r.text,"html.parser")
houst_list=soup.find_all('li',class_='clear')
for house in houst_list:
name=house.find('div',class_='title').a.text.strip()+'\n'
houst_info=house.find('div',class_='houseInfo').text.strip()
houst_info=re.sub('\s+','',houst_info)+'\n'
total_money=str(house.find('div',class_='totalPrice').span.text.strip())+'万'
aver_money=str(house.find('div',class_='unitPrice').span.text.strip())
adderess=house.find('div',class_='positionInfo').a.text.strip()
text_="标题:"+name+"房屋信息:"+houst_info+"总价:"+total_money+' '+aver_money+adderess
with open ('haha.txt',"a+") as f:
f.write(text_)

结果返回一个haha.txt的文本,内容如下:

Python爬虫系统化学习(3)的更多相关文章

  1. Python爬虫系统化学习(4)

    Python爬虫系统化学习(4) 在之前的学习过程中,我们学习了如何爬取页面,对页面进行解析并且提取我们需要的数据. 在通过解析得到我们想要的数据后,最重要的步骤就是保存数据. 一般的数据存储方式有两 ...

  2. Python爬虫系统化学习(5)

    Python爬虫系统化学习(5) 多线程爬虫,在之前的网络编程中,我学习过多线程socket进行单服务器对多客户端的连接,通过使用多线程编程,可以大大提升爬虫的效率. Python多线程爬虫主要由三部 ...

  3. Python爬虫系统化学习(2)

    Python爬虫系统学习(2) 动态网页爬取 当网页使用Javascript时候,很多内容不会出现在HTML源代码中,所以爬取静态页面的技术可能无法使用.因此我们需要用动态网页抓取的两种技术:通过浏览 ...

  4. Python爬虫系统学习(1)

    Python爬虫系统化学习(1) 前言:爬虫的学习对生活中很多事情都很有帮助,比如买房的时候爬取房价,爬取影评之类的,学习爬虫也是在提升对Python的掌握,所以我准备用2-3周的晚上时间,提升自己对 ...

  5. 一个Python爬虫工程师学习养成记

    大数据的时代,网络爬虫已经成为了获取数据的一个重要手段. 但要学习好爬虫并没有那么简单.首先知识点和方向实在是太多了,它关系到了计算机网络.编程基础.前端开发.后端开发.App 开发与逆向.网络安全. ...

  6. python爬虫专栏学习

    知乎的一个讲python的专栏,其中爬虫的几篇文章,偏入门解释,快速看了一遍. 入门 爬虫基本原理:用最简单的代码抓取最基础的网页,展现爬虫的最基本思想,让读者知道爬虫其实是一件非常简单的事情. 爬虫 ...

  7. Python爬虫的学习经历

    在准备学习人工智能之前呢,我看了一下大体的学习纲领.发现排在前面的是PYTHON的基础知识和爬虫相关的知识,再者就是相关的数学算法与金融分析.不过想来也是,如果想进行大量的数据运算与分析,宏大的基础数 ...

  8. python爬虫scrapy学习之篇二

    继上篇<python之urllib2简单解析HTML页面>之后学习使用Python比较有名的爬虫scrapy.网上搜到两篇相应的文档,一篇是较早版本的中文文档Scrapy 0.24 文档, ...

  9. 【Python爬虫案例学习】下载某图片网站的所有图集

    前言 其实很简短就是利用爬虫的第三方库Requests与BeautifulSoup. 其实就几行代码,但希望没有开发基础的人也能一下子看明白,所以大神请绕行. 基本环境配置 python 版本:2.7 ...

随机推荐

  1. Think in Java 第四 五 章

    Think in Java 第四章 控制执行流程 测试while public class whileTest { static boolean condition(){ boolean result ...

  2. C - C(换钱问题)

    换钱问题: 给出n种钱,m个站点,现在有第 s种钱,身上有v 这么多: 下面 m行 站点有a,b两种钱,rab a->b的汇率,cab a-->b的手续费, 相反rba cba :  问在 ...

  3. [The Preliminary Contest for ICPC Asia Nanjing 2019] L-Digit sum

    题意 $S_{b}(n)$表示数字$n$在$b$进制下各位的和,对于给定的数$N$和$b$,求出$\sum_{n=1}^{N}S_{b}(n)$ $[ link ]$ 分析 题解上写的是签到题,这是个 ...

  4. 牛客15334 Easygoing Single Tune Circulation(后缀自动机+字典树)

    传送门:Easygoing Single Tune Circulation 题意 给定n个字符串 s[i],再给出m个查询的字符串 t[i],问 t[i] 是否为某个 s[i] 循环无限次的子串. 题 ...

  5. NYOJ746——整数划分(四)

    描述 暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷..亲爱的你能帮帮他吗? 问题是我们经常见到的整 ...

  6. Codeforces Round #667 (Div. 3) E. Two Platforms (双指针)

    题意:有\(n\)个点往下落,你可以在最下面放两个长度为\(k\)的板子,问做多能接到多少个点. 题解:这题给纵坐标\(y\)完全没有用,我们先对横坐标\(x\)排序,然后从左边开始枚举,用\(l[i ...

  7. PowerShell随笔6---ISE

    简单的命令可以通过控制台窗口输入执行,但是我的脚本逻辑复杂,需要保存.总不能在命令行工具中执行吧. 关了窗口,啥都没了.有没有一个IDE,有. 在PowerShell命令行窗口中输入:ISE,就会打开 ...

  8. Django的settings配置文件

    一.邮件配置 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.qq.com' EMAI ...

  9. FZU2105 Digits Count(按位建线段树)题解

    题意: 给出区间与.或.异或\(x\)操作,还有询问区间和. 思路: 因为数比较小,我们给每一位建线段树,这样每次只要更新对应位的答案. 与\(0\)和或\(1\)相当于重置区间,异或\(1\)相当于 ...

  10. 牛客多校第九场H Cutting Bamboos(主席树 区间比k小的个数)题解

    题意: 标记为\(1-n\)的竹子,\(q\)个询问,每次给出\(l,r,x,y\).要求为砍区间\(l,r\)的柱子,要求砍\(y\)次把所有竹子砍完,每次砍的时候选一个高度,把比他高的都砍下来,并 ...