1、正则表达式

爬虫的四个主要步骤:

  1. 明确目标(要知道你准备取哪个范围或者网站上取搜索)
  2. 爬(将所有网站的内容全部爬下来)
  3. 取(取掉对我们没用的数据)
  4. 处理数据(按照我们想要的方式存储和使用)

什么是正则表达式?

正则表达式(regular expression),又称为规则表达式,描述了一种字符串匹配的模式(pattern),通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式是由普通字符(例如字符a到z)+ 特殊字符(称为“元字符”)组成的文字模式。

正则表达式被广泛的集成到各种文本编辑器/文本处理工具当中

应用场景

  1. 验证: 表单提交时,进行用户名密码的验证
  2. 查找: 从大量信息中快速提取指定内容,在一批url中,查找指定的url,通常用于爬虫
  3. 替换: 将指定格式的文本进行正则匹配查找,找到之后进行特定替换

基本要素

  1. 字符串
  2. 数量限定符
  3. 位置限定符
  4. 预定义字符集

1、字符类

语法 说明 表达式实例 完整匹配的字符串
一般字符 匹配自身 abc abc
. 匹配任意除了换行符"\n"外的字符 a.c abc
\ 转义字符,使后一个字符改变原来的意思 a.c a.c
[…] 匹配[ ]内任一字符。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。如果第一个字符是^则表示取反,如[^abc]表示不是abc的其他字符。 a[bcd]e abe、ace、ade
- 在[ ]内表示字符范围 wo[a-c]ld woald、wocld

2、数量限定符

字符 含义 举例 匹配的字符串
* 匹配前一个字符0次或者无限次 abc* ab、abccccc
匹配前一个字符0次或1次 abc? ab、abc
+ 匹配前一个字符1次或者无限次 abc+ abc、abcccc
{m} 匹配前一个字符m次 ab{2}c abbc
{m,n} 匹配前一个字符m至n次。m和n可以省略:若省略m,则匹配0至n次;若省略n,则至少匹配m次。 ab{1,2}c abc、abbc

3、位置限定符

4、预定义字符集

5、逻辑、分组

re模块一般使用步骤

  1. 使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象
  2. 通过 Pattern 对象对文本进行匹配查找,获得匹配结果,一个 Match 对象。
  3. 使用 Match 对象提供的属性和方法获得信息,根据需要进行其他的操作


正则表达式实现步骤:

# 1.使用compile()函数将正则表达式的字符串形式编译为一个Pattern对象
# 注意:re对特殊字符进行转义, 如果使用原始字符串,只需加一个r前缀
import retext = "2020-12-12 2019-5-3 2020/10/10"pattern = re.compile(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})') # 命名分组
# 2.通过Pattern对象对文本进行匹配查找,获得匹配结果,一个Match对象
# search从给定的字符串中寻找一个符合规则的字符串,返回回来一个
result = re.search(pattern, text)print(result)# 3.使用Match对象提供的属性和方法获取信息,根据需要进行操作
print(result.group())  # 返回的是匹配到的文本信息  2020-12-12
print(result.groups()) # 返回的是位置分组信息  ('2020', '12', '12')
print(result.groupdict()) #返回的是关键字分组信息 {'year': '2020', 'month': '12', 'day': '12'}

Pattern对象

正则表达式编译成 Pattern 对象, 可以利用 pattern 的一系列方法对文本进行匹配查找了。

Pattern 对象的一些常用方法主要有:

  • match 方法:从起始位置开始查找,一次匹配
  • search 方法:从任何位置开始查找,一次匹配
  • findall 方法:全部匹配,返回列表
  • finditer 方法:全部匹配,返回迭代器
  • split 方法:分割字符串,返回列表
  • sub 方法:替换

match方法

match 方法用于查找字符串的头部(也可以指定起始位置),它是一次匹配,只要找到了一个匹配的结果就返回, 而不是查找所有匹配的结果。它的一般使用形式如下:

  • string 待匹配的字符串
  • pos 字符串的起始位置, 默认值是 0
  • endpos 字符串的终点位置, 默认值是 len (字符串长度)

re模块常量

常量即表示不可更改的变量,一般用于做标记。下图是常用的四个模块常量:

Match对象

  • group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
  • start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
  • end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
  • span([group]) 方法返回 (start(group), end(group))。

search方法

search 方法用于查找字符串的任何位置,它也是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有 匹配的结果,它的一般使用形式如下:

当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None。

findall方法与finditer方法

findall 方法搜索整个字符串,获得所有匹配的结果。使用形式如下:


finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每 一个匹配结果(Match 对象)的迭代器。

split方法

split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:

  • maxsplit 指定最大分割次数,不指定将全部分割

sub方法

sub 方法用于替换。它的使用形式如下:

  • repl 可以是字符串也可以是一个函数:
       1). 如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还 可以使用 id 的形式来引用分组,但不能使用编号 0;
       2). 如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符 串中不能再引用分组)。
  • count 用于指定最多替换次数,不指定时全部替换。

正则split和sub方法:

import retext = "1+2-3*4-5/5"
# ************split**************
pattern = re.compile(r'\+|-|\*|/')
result = re.split(pattern, text)
print(result)# *************sub**********
def repl_string(matchObj):items = matchObj.groups()print(items)return '-'.join(items)text = '2010/10/10 2020/12/12 2010-5-3'
pattern = re.compile(r'(\d{4})/(\d{1,2})/(\d{1,2})')
result = re.sub(pattern,repl_string, text)
print(result)['1', '2', '3', '4', '5', '5']
('2010', '10', '10')
('2020', '12', '12')
2010-10-10 2020-12-12 2010-5-3

贪婪模式和非贪婪模式

  1. 贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 ( * );
    使用贪婪的数量词的正则表达式 ab* ,匹配结果: abbb。* 决定了尽可能多匹配 b,所以a后面所有的 b 都出现了。
  2. 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 ( ? );
    使用非贪婪的数量词的正则表达式 ab*? ,匹配结果: a。
    即使前面有 * ,但是 ? 决定了尽可能少匹配 b,所以没有 b。
  3. Python里数量词默认是贪婪的。

基于requests和正则的猫眼电影TOP100定向爬虫:
项目介绍: 应用requests库和正则表达式来抓取猫眼电影TOP100的电影名称、时间、评分、图片等信息。

项目分析:
1. 需求分析,明确采集的网址。
https://maoyan.com/board
2. 爬, requests数据采集库
3. 取,正则表达式数据解析库
4. 存, json格式存储到文件

import codecs
import json
import re
import time
from urllib.error import HTTPErrorimport requests
from colorama import Fore
from fake_useragent import UserAgentdef down_page(url):try:ua = UserAgent()headers = {'User-Agent':ua.random,'Cookie':'__mta=49747353.1586608791319.1586618569026.1586618581654.11; uuid_n_v=v1; uuid=73354BA07BAE11EA81AF6B12644ABFB70CD0E584BFFF4456AE4AA96286336568; _csrf=1d3978fad0d68febffd13896596effb6fa9633349bd601af3678a1bcd78c47b9; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1586608791,1586609306; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1586618649; _lxsdk_cuid=1716940dec2c8-018cbd125127c58-3e6e4647-100200-1716940dec2c8; _lxsdk=73354BA07BAE11EA81AF6B12644ABFB70CD0E584BFFF4456AE4AA96286336568; mojo-uuid=1a2bc23bad16f412c35c00f9b881946a; __mta=49747353.1586608791319.1586618086296.1586618566417.10; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; _lxsdk_s=17169b3dce9-5ef-6b5-ccd%7C%7C28; mojo-trace-id=20; mojo-session-id={"id":"05adcf6f220fcf28a22a52d7640319db","time":1586616327477}','Host':'maoyan.com',}response = requests.get(url, headers=headers)except HTTPError as e:print(Fore.RED + '[-] 爬取网页%s失败:%s' %(url, e.reason))return Noneelse:return response.textdef parse_html(html):"""通过正则表达式对html解析获取电影名称、时间、排行、图片等信息"""pattern = re.compile('<dd>'+ '.*?<i class="board-index.*?">(\d+)</i>' # <i class="board-index board-index-1">1</i>+ '.*?<img data-src="(.*?)" alt="(.*?)"'# <img data-src="xxxxxx" alt="我和我的祖国" >+ '.*?<p class="star">(.*?)</p>'         #<p class="star">主演:黄渤,张译,韩昊霖</p>+ '.*?<p class="releasetime">(.*?)</p>' #<p class="releasetime">上映时间:2019-09-30</p>+ '.*?</dd>',re.S)# finditer返回的是迭代器, findall返回的是列表items = re.finditer(pattern, html)for item in items:yield {'index':item.groups()[0],'image':item.groups()[1],'title':item.groups()[2],'star':item.groups()[3].strip().lstrip('主演:'),'releasetime':item.groups()[4].lstrip('上映时间:')}def save_to_json(data, filename):"""将爬取的数据写入json文件"""# with open(filename, 'ab') as f:#     f.write(json.dumps(data, ensure_ascii=False, indent=4).encode('utf-8'))#     print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' %(data['title']))with codecs.open(filename, 'a', 'utf-8') as f:f.write(json.dumps(data, ensure_ascii=False, indent=4))print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' % (data['title']))def get_one_page(page=1):# url = 'https://maoyan.com/board/'url = 'https://maoyan.com/board/4?offset=%s' %((page-1)*10)html = down_page(url)# print(html)items = parse_html(html)# print(items)# item是字典for item in items:save_to_json(item, 'maoyanTop100.json')def use_multi_thread():# 使用多线程实现from threading import Threadfor page in range(1, 11):thread = Thread(target=get_one_page, args=(page,))thread.start()print(Fore.GREEN + '[+]采集第%s页数据成功' % (page))def use_thread_pool():# 使用线程池from concurrent.futures import ThreadPoolExecutor# 实例化线程池并指定线程池的线程个数pool = ThreadPoolExecutor(100)pool.map(get_one_page, range(1, 11))print('采集结束')if __name__ == '__main__':# for page in range(1,11):#     get_one_page(page)#     print(Fore.GREEN + '[+]采集第%s页数据成功' %(page))#     # 反爬虫策略:防止爬虫速度过快被限速,在采集数据的过程中,休眠一段时间#     time.sleep(0.5)# 使用多线程# use_multi_thread()# 使用线程池use_thread_pool()

2、XPath数据解析库

什么是XPath?

lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高。
XPath (XML Path Language) 是一门在 xml文档中查找信息的语言,可用来在 xml /html文档中对元素和属性进行遍历。

查询更多XPath的用法: https://www.w3school.com.cn/xpath/xpath_syntax.asp

XPath如何实现文档解析?

  1. etree库把HTML文档中的字符串解析为Element对象
from lxml import etree
html=etree.HTML(text)
result=etree.tostring(html)
  1. etree库把HTML文档解析为Element对象
html=etree.parse('xxx.html')
result=etree.tostring(html,pretty_print=True)

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。

常用规则汇总

基于requests和XPath的猫眼电影TOP100定向爬虫:

项目介绍: 应用requests库和Xpath来抓取TIOBE编程语言的去年名次、今年名词、编程语言名词、评级和变化率等信息。
项目分析:
1. 需求分析,明确采集的网址。
https://www.tiobe.com/tiobe-index/
2. 爬, requests数据采集库
3. 取,Xpath数据解析库
4. 存, csv格式存储到文件

import codecs
import json
import re
import time
from urllib.error import HTTPErrorimport requests
from colorama import Fore
from fake_useragent import UserAgent
from lxml import etreedef down_page(url):try:ua = UserAgent()headers = {'User-Agent':ua.random,'Cookie':'__mta=49747353.1586608791319.1586618569026.1586618581654.11; uuid_n_v=v1; uuid=73354BA07BAE11EA81AF6B12644ABFB70CD0E584BFFF4456AE4AA96286336568; _csrf=1d3978fad0d68febffd13896596effb6fa9633349bd601af3678a1bcd78c47b9; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1586608791,1586609306; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1586618649; _lxsdk_cuid=1716940dec2c8-018cbd125127c58-3e6e4647-100200-1716940dec2c8; _lxsdk=73354BA07BAE11EA81AF6B12644ABFB70CD0E584BFFF4456AE4AA96286336568; mojo-uuid=1a2bc23bad16f412c35c00f9b881946a; __mta=49747353.1586608791319.1586618086296.1586618566417.10; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; _lxsdk_s=17169b3dce9-5ef-6b5-ccd%7C%7C28; mojo-trace-id=20; mojo-session-id={"id":"05adcf6f220fcf28a22a52d7640319db","time":1586616327477}','Host':'maoyan.com',}response = requests.get(url, headers=headers)except HTTPError as e:print(Fore.RED + '[-] 爬取网页%s失败:%s' %(url, e.reason))return Noneelse:return response.textdef parse_html(html):"""通过Xpath对html解析获取电影名称、时间、排行、图片等信息"""# 1.将传入的文档内容通过lxml解析器进行解析html = etree.HTML(html)# 2. 通过Xpath语法获取电影的信息movies = html.xpath('//dl[@class="board-wrapper"]/dd')for movie in movies:index = movie.xpath('./i/text()')[0],image = movie.xpath('.//img[@class="board-img"]/@data-src')[0]title = movie.xpath('.//img[@class="board-img"]/@alt')[0]star  = movie.xpath('.//p[@class="star"]/text()')[0]releasetime = movie.xpath('.//p[@class="releasetime"]/text()')[0]yield {'index': index,'image': image,'title': title,'star': star.strip().lstrip('主演:'),'releasetime': releasetime.lstrip('上映时间:')}def save_to_json(data, filename):"""将爬取的数据写入json文件"""# with open(filename, 'ab') as f:#     f.write(json.dumps(data, ensure_ascii=False, indent=4).encode('utf-8'))#     print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' %(data['title']))with codecs.open(filename, 'a', 'utf-8') as f:f.write(json.dumps(data, ensure_ascii=False, indent=4))print(Fore.GREEN + '[+] 保存电影 %s 的信息成功' % (data['title']))def get_one_page(page=1):# url = 'https://maoyan.com/board/'url = 'https://maoyan.com/board/4?offset=%s' %((page-1)*10)html = down_page(url)# print(html)items = parse_html(html)# print(items)# item是字典for item in items:save_to_json(item, 'maoyanTop100.json')if __name__ == '__main__':for page in range(1,11):get_one_page(page)print(Fore.GREEN + '[+]采集第%s页数据成功' %(page))# 反爬虫策略:防止爬虫速度过快被限速,在采集数据的过程中,休眠一段时间time.sleep(0.5)

基于requests和Xpath的TIOBE编程语言排行榜定向爬虫:

import csv
import json
import os
import re
import time
from urllib.error import HTTPErrorimport requests
from colorama import Fore
from fake_useragent import UserAgent
from lxml import etreedef down_page(url):try:ua = UserAgent()headers = {'User-Agent':ua.random,}response = requests.get(url, headers=headers)except HTTPError as e:print(Fore.RED + '[-] 爬取网页%s失败:%s' %(url, e.reason))return Noneelse:return response.textdef parse_html(html):"""通过Xpath对html解析获取编程语言的去年名次,今年名次,编程语言名称,评级Rating和变化率Change等信息"""# 1.将传入的文档内容通过lxml解析器进行解析,返回Element信息html = etree.HTML(html)# 2. 通过Xpath语法获取编程语言相关的信息languages = html.xpath('//table[@id="top20"]/tbody/tr')for language in languages:now_rank = language.xpath('./td[1]/text()')[0]last_rank = language.xpath('./td[2]/text()')[0]name = language.xpath('./td[4]/text()')[0]rating = language.xpath('./td[5]/text()')[0]change = language.xpath('./td[6]/text()')[0]yield {'now_rank': now_rank,'last_rank': last_rank,'name': name,'rating': rating,'change': change}def save_to_csv(data, filename):"""将爬取的数据写入csv文件"""# 1). data是yield返回的字典对象# 2). 以追加的方式打开文件并写入# 3). 文件的编码格式是utf-8# 4). 默认csv文件会写入空行, 解决:newkine:''with open(filename, 'a', encoding='utf-8', newline='') as f:csv_write = csv.DictWriter(f, ['now_rank', 'last_rank', 'name', 'rating', 'change'])# 写入csv文件的表头# csv_write.writeheader()csv_write.writerow(data)def get_one_page(page=1):url = 'https://www.tiobe.com/tiobe-index/'html = down_page(url)# print(html)filename = 'tiobe.csv'# print(os.path.dirname(filename))items = parse_html(html)# print(items)# item是字典for item in items:save_to_csv(item, filename)print(Fore.GREEN + '[+] 写入文件%s成功' %(filename))if __name__ == '__main__':get_one_page()

3、BeautifulSoup(BS4)数据解析库

Beautiful Soup就是Python的一个HTML或XML的解析库,可以用它来方便地从网页中提取数据。Beautiful Soup在解析时实际上依赖解析器, 可以选择的解析器如下表所示:

基本用法

from bs4 import BeautifulSoup
# BeaufulSoup对象的初始化, 并指定html解析器是lxml
soup = BeautifulSoup(html, 'lxml')
# 把要解析的字符串以标准的缩进格式输出
soup.prettify()
# 1. 从bs4模块中导入BeautifulSoup
from bs4 import BeautifulSoup# 2. 实例化BeautifulSoup对象,并通过指定的解析器解析html字符串的内容
html = """
<h1> BS4 </h1>
"""soup = BeautifulSoup(html, 'lxml')# 3. 将要解析的字符串以标准的缩进形式输出
print(soup.prettify())

BeautifulSoup选择器

1、节点选择器

直接调用节点的名称就可以选择节点元素,再调用string属性就可以得到节点内的文本了,这种选择方式速度非常快。如果单个节点结构层次非常清晰,可以选用这种方式来解析。

  1. 选择元素: soup.title, soup.head, soup.p, soup.h1, soup.a.img
  2. 提取信息: soup.title.string, soup.title.class, soup.title.attrs, soup.title.attrs[‘id’]

html = """
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title class="mytitle">beautifulsoup</title>
</head>
<body><table class="table" id="userinfo"><tr><td>姓名</td><td>年龄</td></tr><tr><td>张三</td><td>20</td></tr><tr><td>李四</td><td>22</td></tr></table><div><img src="test.html" title="image title" alt="image alt"></div>
</body>
</html>
"""# 1. 从bs4模块中导入BeautifulSoup
from bs4 import BeautifulSoup# 2. 实例化BeautifulSoup对象,并通过指定的解析器解析html字符串的内容
soup = BeautifulSoup(html, 'lxml')# 3. 节点选择器
# 3-1. 元素选择:只返回在html里面查询符合条件的第一个标签内容
# print(soup.title)
# print(soup.img)
# print(soup.tr)# 3-2. 嵌套选择器
# print(soup.body.table.tr.td)
# print(soup.body.table.tr)# 3-3. 属性选择
# 3-3-1. 获取标签的名称:当爬虫过程中, 标签对象赋值给一个变量传递进函数时,想获取变量对应的标签,name属性就很有用
# print(soup.img.name)# 3-3-2. 获取标签的属性
# print(soup.table.attrs)
# print(soup.table.attrs['class'])
# print(soup.table['class'])
# print(soup.table['id'])# 3-3-3. 获取文本内容
# print(soup.title.string)
# print(soup.title.get_text())# 3-4.  关联选择
# 3-4-1. 父节点和祖父节点
first_tr_tags = soup.table.tr
# print(first_tr_tags.parent) # 父节点
# print(first_tr_tags.parents) # 祖父节点
# parents = first_tr_tags.parents
# for parent in parents:
#     print('*********************')
#     print(parent)# 3-4-2. 子节点和子孙节点
# table_tags = soup.table
# for children  in table_tags.children:
#     print('*****')
#     print(children)# 3-4-3. 兄弟节点
# tr_tag = soup.table.tr
# # print(tr_tag)
# print(tr_tag.next_sibling.next_sibling)

2、方法选择器

节点选择器速度非常快,但面对复杂的选择不够灵活。Beautiful Soup提供的查询方法,比如find_all()和find()等实现灵活查询。

  • find_all方法,查询所有符合条件的元素。
        find_all(name , attrs , recursive , text , **kwargs)
        soup.find_all(name=‘ul’), soup.find_all(attrs={‘id’: ‘list-1’}),
      soup.find_all(class_=‘element’),
      soup.find_all(text=re.compile(‘link’))
  • find()方法,返回第一个匹配的元素

import refrom bs4 import BeautifulSouphtml = """
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title class="mytitle">beautifulsoup</title>
</head>
<body><table class="table" id="userinfo"><tr class="item-1"><td>姓名</td><td>年龄</td></tr><tr class="item-2"><td>张三</td><td>20</td></tr><tr class="item-3"><td>李四</td><td>22</td></tr></table><div><img src="test.html" title="image title" alt="image alt"></div>
</body>
</html>
"""soup = BeautifulSoup(html, 'lxml')# print(soup.find_all(name='table'))# print(soup.find_all('table',attrs={'id':'userinfo'}))
# print(soup.find_all('table', attrs={'class':'table'}))# print(soup.find_all('table', id='userinfo'))
# print(soup.find_all('table', class_='table'))# print(soup.find_all('td', text=re.compile('\d{1,2}'), limit=1))
print(soup.find_all('tr', class_=re.compile('item-\d+'), limit=2))

3、CSS选择器

import refrom bs4 import BeautifulSouphtml = """
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<table class="table" id="userinfo"><tr class="item-1"><td>姓名</td><td>年龄</td></tr><tr class="item-2"><td>张三</td><td>10</td></tr><tr class="item-3"><td>李四</td><td>20</td></tr>
</table>
<div><img src="download_images" title="image" alt="image alt">
</div>
</body>
</html>
"""
soup = BeautifulSoup(html,'lxml')# css选择器
print(soup.select('.item-3'))
#
print(soup.select('#userinfo'))print(soup.select('table tr td'))

项目案例:基于requests和BS4的三国演义名著定向爬虫

  • 爬取的网站:http://www.shicimingju.com/book/
    项目分析:
    1、根据网址http://www.shicimingju.com/book/sanguoyanyi.html获取三国演义主页的章节信息.
    2、分析章节信息的特点, 提取章节的详情页链接和章节的名称。
    <div class=“book-mulu”><ul><li>,li的详情信息如下:
    <li><a href="/book/sanguoyanyi/1.html">第一回·宴桃园豪杰三结义 斩黄巾英雄首立功</a></li>
    3、根据章节的详情页链接访问章节内容


    4、提取到的章节内容包含特殊的标签, eg: <br/> ==> ‘\n’<p>,\ => ‘’
    5、将章节信息存储到文件中
import os
from requests import HTTPErrorimport requests
from bs4 import BeautifulSoup
from colorama import Fore
from fake_useragent import UserAgentdef download_page(url, parmas=None):"""根据url地址下载html页面:param url::param parmas::return: str"""try:ua = UserAgent()headers = {'User-Agent': ua.random,}# 请求https协议的时候, 回遇到报错: SSLError# verify=Flase不验证证书response = requests.get(url, params=parmas, headers=headers)except  HTTPError as e:print(Fore.RED + '[-] 爬取网站%s失败: %s' % (url, str(e)))return Noneelse:# content返回的是bytes类型, text返回字符串类型return response.textdef parse_html(html):# 实例化BeautifulSoup对象,并通过指定的解析器解析html字符串的内容soup = BeautifulSoup(html, 'lxml')# 根据bs4的选择器获取章节的详情页链接和章节名称book = soup.find('div', class_='book-mulu') # 获取该书籍对象chapters = book.find_all('li')  # 获取该数据所有的章节对应的li标签,返回的是列表# 依次遍历每一个章节for chapter in chapters:detail_url = chapter.a['href']# print(detail_url)chapter_name = chapter.a.string# print(chapter_name)yield {'detail_url':detail_url,'chapter_name':chapter_name}def parse_detail_html(html):# 实例化BeautifulSoup对象,并通过指定的解析器解析html字符串的内容soup = BeautifulSoup(html, 'lxml')# chapter_content = soup.find('div', class_='chapter_content')# 根据章节的详情页链接访问章节内容,string只拿出当前标签的文本信息,get_text()返回当前标签和子孙标签的所有文本信息chapter_content = soup.find('div', class_='chapter_content').get_text()# print(chapter_content)return chapter_content.replace(' ', '')def get_one_page():base_url = 'http://www.shicimingju.com'url = 'http://www.shicimingju.com/book/sanguoyanyi.html'dirname = '三国演义'if not os.path.exists(dirname):os.mkdir(dirname)print(Fore.GREEN + "创建书籍目录%s成功" %(dirname))html = download_page(url)items = parse_html(html)for item in items:# 访问详情页链接detail_url = base_url + item['detail_url']# 生成文件存储路径chapter_name = os.path.join(dirname, item["chapter_name"] + '.txt')chapter_html = download_page(detail_url)chapter_content = parse_detail_html(chapter_html)# 写入文件with open(chapter_name, 'w', encoding='utf-8') as f:f.write(chapter_content)print(Fore.GREEN + '写入文件%s成功' %(chapter_name))if __name__ == '__main__':get_one_page()

爬虫之网络数据解析的三种方式---正则表达式、XPath数据解析库、BeautifulSoup数据解析库相关推荐

  1. android xml解析的三种方式

    2019独角兽企业重金招聘Python工程师标准>>> 在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX.Pull.Dom解析方式.最近做了 ...

  2. 微服务中数据聚合的三种方式

    在微服务暴热的情形下,似乎不弄点微服务,已经是跟不上IT的大潮了. 因此,公司结合本身情况,以及将来的可拓展性,在我的主导下,在新的项目中采用了微服务架构 然而,实施过程中遇到一个挠头的问题,就是数据 ...

  3. 爬虫之数据解析的三种方式

    一,正则表达式解析 re正则就不写了,前面已经写入一篇很详细的正则表达式模块了~ 而且,在爬虫中,下面两种方式用的多一些~ 正则表达式:https://www.cnblogs.com/peng104/ ...

  4. Python数据解析的三种方式

    一,正则表达式解析 在爬虫中,下面两种方式用的多一些~ 大致用法: pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i&g ...

  5. 解析XML三种方式(PULL、SAX、DOM)

    本篇博客重点介绍Android中三种解析XML的方式,包括PULL.SAX.DOM,当然不止这些,还可以用第三方的jar包提供的解析,只是这三种在Android中比较常用吧.再顺便介绍一下Androi ...

  6. Android解析XML三种方式(PULL、SAX、DOM)

    本篇博客重点介绍Android中三种解析XML的方式,包括PULL.SAX.DOM,当然不止这些,还可以用第三方的jar包提供的解析,只是这三种在Android中比较常用吧.再顺便介绍一下Androi ...

  7. Android数据存储的三种方式-SharedPrefrences,File,SQLite

    1,使用SharedPrefrences 用于简单少量的数据,数据的格式简单:都是普通的字符串,标量类型的值等,比如各种配置信息等等 SharedPrefrences与Editor简介: 创建Shar ...

  8. PHP中数据类型转换有多少种,PHP中数据类型转换的三种方式

    PHP的数据类型转换属于强制转换,允许转换的PHP数据类型有: 1.(int).(integer):转换成整形 2.(float).(double).(real):转换成浮点型 3.(string): ...

  9. JdbcTemplate 查询数据实现的三种方式

    JdbcTemplate 在对数据库进行查询时,通常通过实现下面三种回调接口之一实现 org.springframework.jdbc.core.ResultSetExtractororg.sprin ...

最新文章

  1. 周志华:Boosting学习理论的探索 —— 一个跨越30年的故事
  2. urlencode和quote的用法
  3. python自建模块导入_Python模块的使用及自建模块的导入方法举例
  4. FileZilla搭建FTP服务器图解教程
  5. centos 搭建web平台
  6. html post请求 渲染,FastAPI框架入门 基本使用, 模版渲染, form表单数据交互, 上传文件, 静态文件配置...
  7. 系统集成资质-信息系统项目管理师考试综合介绍
  8. Kubernetes详解(二十二)——Deployment控制器
  9. 谷歌翻译用不了解决办法
  10. 因果信号的傅里叶变换_信号傅里叶变换系列文章(1):傅里叶级数、傅里叶系数以及傅里叶变换...
  11. gtx1050ti最稳定的驱动_笔记本1050ti显卡安装最新驱动版本 (415.27) 记录 NVIDIA显卡GeForce系列...
  12. 有哪些好的科研工具软件?
  13. 【sketchup 2021】草图大师的编辑工具2【路径跟随、偏移与轴、卷尺工具和尺寸、绘制参考线】
  14. 项目升级与环境变化架构侧重点
  15. 适配ipad Pro
  16. 互联网医院系统软件开发|互联网医院管理系统开发的好处
  17. Windows下PostgreSQL 8.1版安装图解
  18. 微信开发(1):VM331:2 未找到 pages/index/index.wxml 文件
  19. pr怎么把视频去水印
  20. 为什么需要虚拟DOM?

热门文章

  1. js处理字符串、数组的方法
  2. pat甲级考试报名费_PAT(甲级)2019年冬季考试 题解
  3. 有没有什么颜值测试软件,教一教大家怎么用微信颜值测试软件
  4. java 数组作为方法参数
  5. cocos2dx---游戏摇杆类(观察者模式控制英雄移动)
  6. 基础服务之ntp服务
  7. Pssh -- 使用单个终端在多个远程Linux服务器上执行命令
  8. 新一代 AirPods 充电仓曝光: 入耳式设计看起来更类似 AirPods Pro 的设计
  9. layer ajax 输入框,layui几种常用输入框
  10. 帝国CMS7.5仿《3500游戏》源码/大气H5游戏门户网站模板/H5游戏在线网站源码