Python网络爬虫进阶+正则表达式
- 1 HTML基础
- 1.1 HTML结构
- 1.2 HTML各标签结构
- 1.3 HTML样式
- 2.正则表达式
- 2.1 元字符
- 2.1.1 元字符之. ^ $ * + ? { }
- 2.1.2 元字符之字符集[]
- 2.1.3 元字符之转义符 \
- 2.1.4 元字符之分组()
- 2.1.4 元字符之|
- 2.1.5 正则表达式模式总结
- 2.2 re模块下的常用方法
- 2.1 元字符
- 爬虫案例 1
- 3 Beautiful Soup
- 3.1 创建 Beautiful Soup 对象并打印对象内容
- 3.2 四大对象种类
- 3.3常用方法
- 代码实例
- 爬虫案例 2
1 HTML基础
1.1 HTML结构
HTML是超文本标记语言,被web浏览器进行解析查看。它的文档制作简单,功能强大 ,支持很多其他格式文件的嵌入。”超文本“文档主要由头部(head)和主体(body )两部分组成
<head> 定义了文档的信息
<title> 定义了文档的标题
<base> 定义了页面链接标签的默认链接地址
<link> 定义了一个文档和外部资源之间的关系
<meta> 定义了HTML文档中的元数据
<script> 定义了客户端的脚本文件
<style> 定义了HTML文档的样式文件
1.2 HTML各标签结构
- div是标签名
- id是为该标签设置的唯一标识
- class是该标签的样式类
- attr是设置的其他属性
- content是的标签的文本内容
1.3 HTML样式
- id选择器:#id_name,选择id=id_name的所有元素
- 类选择器:.cls_name,选择class=cls_name的所有元素
- 标签选择:lable,选择标签名为lable的所有元素,用逗号隔开可选择多个标签
- 全部选择:*,选择所有的元素
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>网页标题</title><style>*{ /*通配符*/font-size:50px;}h1{ /*标签选择器*/color:red;}div.content{ /*类选择器,不唯一,可以多个标签使用同一个class名*/background-color:blue;}#name{ /*id选择器*/border: 4px solid red;}a span{ /*选中a标签内的所有span标签*/color:maroon;}a>span{ /*只选中a标签的第一级子标签中的span*/}a[title="新浪"]{}</style>
</head>
<body><h1>演示HTML文件</h1><span>这是一个span标签</span><a href="http://www.baidu.com"><div><span>跳转到百度网</span></div></a><h1>第二个标题</h1><div class="content">这是网页内容</div><h3 id="name">用户名:张三</h3><p class="content">这是一篇文章</p><a href="http://www.sina.com" title="新浪">新浪网</a></body>
</html>
运行结果:
2.正则表达式
正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
字符匹配(普通字符,元字符):
1 普通字符:大多数字符和字母都会和自身匹配
re.findall('alvin','yuanaleSxalexwupeiqi')
#['alvin']
2 元字符:. ^ $ * + ? { } [ ] | ( ) \
2.1 元字符
2.1.1 元字符之. ^ $ * + ? { }
import reret=re.findall('a..in','helloalvin')
print(ret)#['alvin']ret=re.findall('^a...n','alvinhelloawwwn')
print(ret)#['alvin']ret=re.findall('a...n$','alvinhelloawwwn')
print(ret)#['awwwn']ret=re.findall('a...n$','alvinhelloawwwn')
print(ret)#['awwwn']ret=re.findall('abc*','abcccc')#贪婪匹配[0,+oo]
print(ret)#['abcccc']ret=re.findall('abc+','abccc')#[1,+oo]
print(ret)#['abccc']ret=re.findall('abc?','abccc')#[0,1]
print(ret)#['abc']ret=re.findall('abc{1,4}','abccc')
print(ret)#['abccc'] 贪婪匹配
#前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
ret=re.findall('abc*?','abcccccc')
print(ret)#['ab']
2.1.2 元字符之字符集[]
ret=re.findall('a[bc]d','acd')
print(ret)#['acd']ret=re.findall('[a-z]','acd')
print(ret)#['a', 'c', 'd']ret=re.findall('[.*+]','a.cd+')
print(ret)#['.', '+']#在字符集里有功能的符号: - ^ \ret=re.findall('[1-9]','45dha3')
print(ret)#['4', '5', '3']ret=re.findall('[^ab]','45bdha3')
print(ret)#['4', '5', 'd', 'h', '3']ret=re.findall('[\d]','45bdha3')
print(ret)#['4', '5', '3']
2.1.3 元字符之转义符 \
反斜杠后边跟元字符去除特殊功能,比如.
反斜杠后边跟普通字符实现特殊功能,比如\d
- \d 匹配任何十进制数;它相当于类 [0-9]。
- \D 匹配任何非数字字符;它相当于类 [^0-9]。
- \s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
- \S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
- \w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
- \W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
- \b 匹配一个特殊字符边界,比如空格 ,&,#等
ret=re.findall('I\b','I am LIST')
print(ret)#[]
ret=re.findall(r'I\b','I am LIST')
print(ret)#['I']#-----------------------------eg1:
import re
ret=re.findall('c\l','abc\le')
print(ret)#[]
ret=re.findall('c\\l','abc\le')
print(ret)#[]
ret=re.findall('c\\\\l','abc\le')
print(ret)#['c\\l']
ret=re.findall(r'c\\l','abc\le')
print(ret)#['c\\l']#-----------------------------eg2:
#之所以选择\b是因为\b在ASCII表中是有意义的
m = re.findall('\bblow', 'blow')
print(m)
m = re.findall(r'\bblow', 'blow')
print(m)
2.1.4 元字符之分组()
m = re.findall(r'(ad)+', 'add')
print(m)ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com')
print(ret.group())#23/com
print(ret.group('id'))#23
2.1.4 元字符之|
ret=re.search('(ab)|\d','rabhdg8sd')
print(ret.group())#ab
2.1.5 正则表达式模式总结
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[…] | 用来表示一组字符,单独列出:[amk] 匹配 ‘a’,’m’或’k’ |
[^…] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。 |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
re{ n} | 匹配n个前面表达式。例如,”o{2}”不能匹配”Bob”中的”o”,但是能匹配”food”中的两个o。 |
re{ n,} | 精确匹配n个前面表达式。例如,”o{2,}”不能匹配”Bob”中的”o”,但能匹配”foooood”中的所有o。”o{1,}”等价于”o+”。”o{0,}”则等价于”o*”。 |
re{ n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 |
aIb | 匹配a或b |
(re) | G匹配括号内的表达式,也表示一个组 |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
(?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
(?: re) | 类似 (…), 但是不表示一个组 |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 |
(?#…) | 注释. |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。 |
(?> re) | 匹配的独立模式,省去回溯。 |
\w | 匹配数字字母下划线 |
\W | 匹配非数字字母下划线 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]。 |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配”never” 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。 |
\B 匹配非单词边界。 | ‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。 |
\n, \t, 等。 | 匹配一个换行符。匹配一个制表符, 等 |
\1…\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
2.2 re模块下的常用方法
import re
#1
re.findall('a','alvin yuan') #返回所有满足匹配条件的结果,放在列表里
#2
re.search('a','alvin yuan').group() #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。#3
re.match('a','abc').group() #同search,不过尽在字符串开始处进行匹配#4
ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret)#['', '', 'cd']#5
ret=re.sub('\d','abc','alvin5yuan6',1)
print(ret)#alvinabcyuan6
ret=re.subn('\d','abc','alvin5yuan6')
print(ret)#('alvinabcyuanabc', 2)#6
obj=re.compile('\d{3}')
ret=obj.search('abc123eeee')
print(ret.group())#123
ort re
ret=re.finditer('\d','ds3sy4784a')
print(ret) #<callable_iterator object at 0x10195f940>print(next(ret).group())
print(next(ret).group())#注意:import reret=re.findall('www.(baidu|oldboy).com','www.oldboy.com')
print(ret)#['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
print(ret)#['www.oldboy.com']
爬虫案例 1
爬取51job爬虫所爬取的职位信息数据,并将数据保存进excel中
import re
import requests
import xlwturl = "https://search.51job.com/list/020000,000000,0000,00,9,99,python,2,{}.html?lang=c&stype=1&postchannel=0000&workyear=99&cotype=99°reefrom=99&jobterm=99&companysize=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare="# 爬取第一页数据
firstpage = url.format(1)
response = requests.get(firstpage)# 转化成gbk编码
html = str(response.content, "gbk")# print(html)# 获取总页数
pattern = re.compile('<span class="td">共(.*?)页,到第</span>', re.S)result = re.findall(pattern, html)totalPage = int(result[0])
# print("总页数:{}".format(totalPage))# 循环爬取所有数据
for page in range(1, 11):#这里仅爬取十页信息# print("---------------正在爬取第{}页数据---------------".format(page))# 组装当前页的页码currentUrl = url.format(page)# print(currentUrl[0:80])response = requests.get(currentUrl)html = str(response.content, "gbk")reg = re.compile('class="t1 ">.*? <a target="_blank" title="(.*?)".*? <span class="t2"><a target="_blank" title="(.*?)".*?<span class="t3">(.*?)</span>.*?<span class="t4">(.*?)</span>.*? <span class="t5">(.*?)</span>',re.S) # 匹配换行符#获取一页中所有的职位信息onePage = re.findall(reg,html)#循环输出一页中所有的职位信息# for jobName, company, place, salary, postDate in onePage:# pass# print("名称:{},公司:{},地址:{},薪资:{},发布日期:{}".format(jobName, company, place, salary, postDate))# print("******************************************************")
def excel_write(items,index):for item in items:#职位信息for i in range(0,5):#print item[i]ws.write(index,i,item[i])#行,列,数据# print(index)index += 1
newTable="51job.xls"#表格名称
wb = xlwt.Workbook(encoding='utf-8')#创建excel文件,声明编码
ws = wb.add_sheet('sheet1')#创建表格
headData = ['招聘职位','公司','地址','薪资','日期']#表头信息
for colnum in range(0, 5):ws.write(0, colnum, headData[colnum], xlwt.easyxf('font: bold on')) # 行,列for each in range(1,10):index=(each-1)*50+1excel_write(onePage,index)wb.save(newTable)
运行结果:
3 Beautiful Soup
3.1 创建 Beautiful Soup 对象并打印对象内容
import requests
from bs4 import BeautifulSoup as bshtml = requests.get("https://www.baidu.com").text# print(html
soup = bs(html,"lxml") #html.parser/lxml/html5lib#将html字符串数据美化输出
# print(soup.prettify())
print(soup.name)
3.2 四大对象种类
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是 Python对象,所有对象可以归纳为4种:
- Tag
Tag:就是 HTML 中的一个个标签。 语法形式:soup.标签名 用来查找的是在所有内容中的第一个符合要求的标签 Tag 有两个属性,是 name 和 attrs。 soup 对象的 name 是输出的值便为标签本身的名称。 soup 对象的attrs是把标签的所有属性放在一个字典内
- NavigableString
获取标签内部的文字
soup.标签名.string - BeautifulSoup
- Comment
Comment 对象是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包 括注释符号
3.3常用方法
(1)find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs) 搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件
(2)find(name=None, attrs={}, recursive=True, text=None, **kwargs) 搜索当前tag的第一个tag子节点,并判断是否符合过滤器的条件
movieQuote = movieLi.find(‘span’, attrs={‘class’: ‘inq’})
(3)直接子节点:.contents .children属性
(4)所有子孙节点:.descendants属性
(5)获取文本:.string属性
(6)父节点:.parent .parents(迭代器)
(7)兄弟节点:.next_sibling .previous_sibling 加s同上
(8)下一个与上一个要解析的元素:.next_elements .previous_element
1)name 参数 name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉
2)attrs 参数 注意:如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag 的属性来搜索,如果包含一个名字为 id 的参数,Beautiful Soup会搜索每个tag的”id”属性
3)text 参数 通过 text 参数可以搜搜文档中的字符串内容.与 name 参数的可选值一样, text 参数接受 字 符串 , 正则表达式 , 列表, True
4)limit 参数 find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结 果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果 数量达到 limit 的限制时,就停止搜索返回结果.
5)recursive 参数 调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索 tag的直接子节点,可以使用参数 recursive=False .
代码实例
from bs4 import BeautifulSoup as bshtml = '''
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p><p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">jack</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Alice</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Mary</a>;
and they lived at the bottom of a well.</p><p class="story">...</p>
'''soup = bs(html, "html.parser")# print(soup.prettify())# 获取Tag标签的属性
# print(soup.a["id"])
# print(soup.a.get("id"))
# print(soup.a.get("class"))# 获取标签内的文字
# print(soup.a.string)
# print(soup.b.string)# soup.find()只匹配第一个符合规则的Tag标签
# secondLink = soup.find("a",attrs={"class":"sister"})
# print(secondLink.string)#soup.find_all()匹配所有符合规则的Tag标签# links = soup.find_all("a",attrs={"class":"sister"})
# print(links[1].get("id"))p = soup.find("p")#在p标签内查找b标签
# b = p.find("b")
# print(b)#获取父标签
# xTag = p.parent
# print(xTag.name)#获取所有的父标签
for parent in p.parents:print(parent.name)
爬虫案例 2
爬取豆瓣电影top250条电影数据,并存储进MySQL
import requests
from bs4 import BeautifulSoup as bs
import pymysqlmovieInfos = [] # 用于保存所有的电影信息
baseUrl = 'https://movie.douban.com/top250?start={}&filter='
for startIndex in range(0, 226, 25):url = baseUrl.format(startIndex)# 爬取网页r = requests.get(url)# 获取html内容htmlContent = r.text# 用BeautifulSoup加载html文本内容进行处理soup = bs(htmlContent, "lxml")# 获取到页面中索引的class名为info的标签(应该有25个)movieList = soup.find_all("div", attrs={"class": "info"})# 遍历25条电影信息for movieItem in movieList:movieInfo = {} # 创建空字典,保存电影信息# 获取到名为class名为hd的div标签内容hd_div = movieItem.find("div", attrs={"class": "hd"})# 通过bd_div获取到里面第一个span标签内容hd_infos = hd_div.find("span").get_text().strip().split("\n")# < span class ="title" > 天堂电影院 < / span >movieInfo['title'] = hd_infos[0]# 获取到class名为bd的div标签内容bd_div = movieItem.find("div", attrs={"class": "bd"})# print(bd_div)# 通过bd_div获取到里面第一个p标签内容infos = bd_div.find("p").get_text().strip().split("\n")# print(infos) #包含了两行电影信息的列表# 获取导演和主演infos_1 = infos[0].split("\xa0\xa0\xa0")if len(infos_1) == 2:# 获取导演,只获取排在第一位的导演名字director = infos_1[0][4:].rstrip("...").split("/")[0]movieInfo['director'] = director# 获取主演role = infos_1[1][4:].rstrip("...").rstrip("/").split("/")[0]movieInfo['role'] = roleelse:movieInfo['director'] = NonemovieInfo['role'] = None# 获取上映的时间/地区/电影类型infos_2 = infos[1].lstrip().split("\xa0/\xa0")# 获取上映时间year = infos_2[0]movieInfo['year'] = year# 获取电影地区area = infos_2[1]movieInfo['area'] = area# 获取类型genre = infos_2[2]movieInfo['genre'] = genreprint(movieInfo)movieInfos.append(movieInfo)
conn = pymysql.connect(host='localhost', user='root', passwd='DevilKing27', db='douban',charset="utf8")
# 获取游标对象
cursor = conn.cursor()
# 查看结果
print('添加了{}条数据'.format(cursor.rowcount))
for movietiem in movieInfos:director = movietiem['director']role = movietiem['role']year = movietiem['year']area = movietiem['area']genre = movietiem['genre']title = movietiem['title']sql = 'INSERT INTO top250 values("%s","%s","%s","%s","%s","%s")' % (director, role, year, area, genre, title)# 执行sqlcursor.execute(sql)# 提交conn.commit()print('添加了{}条数据'.format(cursor.rowcount))
结果:
Python网络爬虫进阶+正则表达式相关推荐
- Python网络爬虫和正则表达式学习总结
阅读目录 1.利用urllib2对指定的URL抓取网页内容 2. 使用正则表达式过滤抓取到的网页信息 2.1 正则表达式介绍 2.2 Python的re模块 2.3 Python正则表达式汇总 以前在 ...
- [Python] 网络爬虫和正则表达式学习总结
以前在学校做科研都是直接利用网上共享的一些数据,就像我们经常说的dataset.beachmark等等.但是,对于实际的工业需求来说,爬取网络的数据是必须的并且是首要的.最近在国内一家互联网公司实习, ...
- Python网络爬虫(三) 爬虫进阶
###目录: Python网络爬虫(一)- 入门基础 Python网络爬虫(二)- urllib爬虫案例 Python网络爬虫(三)- 爬虫进阶 Python网络爬虫(四)- XPath Python ...
- python网络爬虫权威指南 豆瓣_福利分享:个人整理的Python书单,从基础到进阶...
原标题:福利分享:个人整理的Python书单,从基础到进阶 我挑选的一些书籍,大家可以自行到书店或是网上自己选购.也由于个人水平有限,很可能大家觉得优秀的书籍没有列出,如果大家有觉得不错的书籍,欢迎大 ...
- Python 网络爬虫笔记6 -- 正则表达式
Python 网络爬虫笔记6 – 正则表达式 Python 网络爬虫系列笔记是笔者在学习嵩天老师的<Python网络爬虫与信息提取>课程及笔者实践网络爬虫的笔记. 课程链接:Python网 ...
- python网络爬虫之解析网页的正则表达式(爬取4k动漫图片)[三]
目录 前言 一.正则表达式的学习 1.正则表达式的匹配工具 2.正则表达式的样式 3.正则表达式的案例 二.爬取网页图片 1.分析网页 2.获取数据 爬取妹子网的案例 后记 前言 hello,大家好 ...
- python网络爬虫系列教程_Python网络爬虫系列教程连载 ----长期更新中,敬请关注!...
感谢大家长期对Python爱好者社区的支持,后期Python爱好者社区推出Python网络爬虫系列教程.欢迎大家关注.以下系列教程大纲,欢迎大家补充.视频长期连载更新中 --------------- ...
- 【读书笔记】Python网络爬虫从入门到实践(第2版)-唐松,爬虫基础体系巩固和常见场景练习
[概述] 书名:Python网络爬虫从入门到实践(第2版) 作者:唐松 日期:2021年08月01日 读书用时:1568页,100小时,59个笔记 [读书笔记] ◆ 1.2 网络爬虫是否合法 爬虫协议 ...
- 《Python网络爬虫从入门到实践 第2版》第14章 爬虫实践一:维基百科
第14章 爬虫实践一:维基百科 "是骡子是马,拉出来遛遛".我们已经将Python网络爬虫的技术系统地学习完了,后面几个章节开始进入实践环节.每一章都会使用之前学习的技术,通过实践 ...
最新文章
- 软件测试安全测试高峰论坛
- UWP开发入门(十六)——常见的内存泄漏的原因
- Python3 configparser 中文乱码
- 静态链接库与动态链接库的优缺点
- 多线程基础与JUC进阶笔记
- (JAVA)Math类
- KandQ:单例模式的七种写法及其相关问题解析
- java设计模式之装饰者模式学习
- 研华自动驾驶计算机,研华全新发布宽温8TB NVMe SSD SQFlash 920系列 为自动驾驶应用保驾护航...
- 使用Echarts绘制省份地图源码
- [神经网络]计算量GFLOPS和参数量#Params以及感受野计算
- JavaWeb调用顺序
- 大学本科计算机专业那些课 左飞
- 如何设置某些动作在凌晨12点时自动更新
- PMP和MBA、MPA的比较
- 家用计算机都是专用计算机吗,什么是因特网概念和互联网一样吗(因特网发展历程)...
- FPGA驱动mipi 光固化 4K屏
- 自称很菜的二本大龄程序员居然拿到百度offer(百度面经)
- gets、puts函数和fgets、fputs函数的区别与联系
- vue配合element 实现在线预览pdf文档