Python网络爬虫【2】--正则表达式、Scrapy库的使用

    技术2022-07-10  135

    单元四、信息组织与提取方法

    1)信息标记的三种方式

    XML, JSON, YAML

    2)信息提取的一般方法

    方法一:完整解析信息的标记形式,再提取关键信息

    XML JSON YAML

    需要标记解析器 例如:bs4库的标记树遍历

    优先:信息解析准确

    缺点:提取过程繁琐,速度慢

    方法二:无标记形式,直接搜索关键信息

    搜索

    对信息的文本查找函数即可。

    优点:提取过程简单,速度较快

    缺点:提取结果准确性与信息内容有关

    方法三:融合方法:结合形式解析与搜索方法,提取关键信息

    XML JSON YAML 搜索

    需要标记解析器及文本查找函数

    实例:提取HTML中所有的URL链接

    思路;1)搜索到所有的标签

    ​ 2)解析标签格式,提取href后的链接内容

    3)基于bs4的HTML内容查找方法

    <tag>.fint_all(name, attrs, recursive, string, **kwargs) 其等价于<tag>(..) 返回: 一个列表类型,存储查找的结果 选项: name: 对标签名称的检索字符串 attrs: 对标签属性值的检索字符串,可标注属性索引 recursive: 是否对子孙全部索引,默认True string: <>...</>中字符串区域的检索字符串 **kwargs:

    参数name:

    >>> soup.find_all('a') ## 查找所有a标签 >>> soup.find_all(['a', 'b']) ## 查找所有a, b标签

    参数attrs:

    >>> soup.find_all('p', 'course') >>> soup.find(id = 'link1')

    参数recursive:

    >>> soup.find_all('a', recursive = True) >>> soup.find_all('a', recursive = False)

    参数string:

    >>> soup.find_all(string = 'Basic Python')

    简写:

    <tag>(…) 等价于 <tag>.find_all(…)

    soup(…) 等价于 soup.find_all(…)

    拓展方法:

    方法说明<>.find()搜索且只返回一个结果,字符串类型,同.find_all()参数<>.find_parents()在先辈节点中搜索,返回列表类型,同.find_all()参数<>.find_parent()在先辈节点中返回一个结果,字符串类型, 同.find_all()参数<>.find_next_siblings()在后续平行节点中搜索,返回列表类型, 同.find_all()参数<>.find_next_sibling()在后续平行节点中返回一个结果,字符串类型, 同.find_all()参数<>.find_previous_siblings()在前续平行节点中搜索,返回列表类型, , 同.find_all()参数<>.find_previous_sibling()在前续平行节点中返回一个结果,字符串类型, 同.find_all()参数

    案例:爬取最好中国大学网

    import requests import bs4 from bs4 import BeautifulSoup def getHTMLText(url): try: r = requests.get(url) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except: return "" def fillUnivList(ulist, html): soup = BeautifulSoup(html, 'html.parser') for tr in soup.find('tbody').children: if isinstance(tr, bs4.element.Tag): tds = tr('td') ulist.append([tds[0].string, tds[1].string, tds[4].string]) def printUnivList(ulist, num): tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}" print(tplt.format("排名", "学校", "总分", chr(12288))) for i in range(num): u = ulist[i] print(tplt.format(u[0], u[1], u[2], chr(12288))) def main(): uinfo = [] url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2020.html' html = getHTMLText(url) fillUnivList(uinfo, html) printUnivList(uinfo, 20) main()

    单元五、正则表达式

    1)正则表达式的概念

    正则表达式的常用操作符

    操作符说明实例.表示任何单个字符串[ ]字符集,对单个字符给出取值范围[abc]表示a、b、c,[a-z]表示a到z单个字符[^ ]非字符集,对单个字符给出排除范围[^abc]表示非a或b或c的单个字符*前一个字符出现0次或无限次拓展abc*表示ab、abc、abcc、abccc等+前一个字符出现1次或无限次拓展abc+表示abc、abcc、abccc等?前一个字符出现0次或1次拓展abc?表示ab、abc|左右表达式任意一个abc|def表示abc、def{m}拓展前一个字符m次ab{2}c表示abbc{m, n}拓展前一个字符m至n次(含n)ab{1, 2}c表示abc、abbc^匹配字符串开头^abc表示abc且在一个字符串的开头$匹配字符串结尾abc$表示abc且在一个字符串的结尾()分组标记,内部只能使用|操作符(abc)表示abc,(abc|def)表示abc、def\d数字,等价于[0-9]\w单词字符,等价于[A-Za-z0-9_]

    2)Re库的使用

    Re库主要功能函数

    函数说明re.search()在一个字符串中搜索匹配正则表达式的第一个位置,返回一个match对象re.match()从一个字符串的开始位置起匹配正则表达式,返回match对象re.findall()搜索字符串,以列表类型返回全部能匹配的子串re.split()将一个字符串按照正则表达式匹配结果进行分割,返回列表类型re.finditer()搜索字符串,返回一个匹配结果的迭代对象,每个迭代对象都是match对象re.sub()在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

    1 re.search()

    re.search(pattern, string, flags=0) 选项: patten: 正则表达式的字符串或原生子串表达式 string: 待匹配字符串 flags: 正则表达式使用时的控制标记

    flags的常用标记:

    常用标记说明re.I re.IGNORECASE忽略正则表达式的大小写,|A-Z|能够匹配小写字符re.M re.MULTILINE正则表达式中的^操作符能够将给定字符串的每行当作匹配开始re.S re.DOTALL正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符

    2 re.match

    re.match(pattern, string, flags=0) 选项: patten: 正则表达式的字符串或原生子串表达式 string: 待匹配字符串 flags: 正则表达式使用时的控制标记

    3 re.findall

    re.findall(pattern, string, flags=0) 选项: patten: 正则表达式的字符串或原生子串表达式 string: 待匹配字符串 flags: 正则表达式使用时的控制标记

    4 re.split

    re.split(pattern, string, maxsplit=0, flags=0) 选项: patten: 正则表达式的字符串或原生子串表达式 string: 待匹配字符串 maxsplits: 最大分割数,剩余部分作为最后一个元素输出 flags: 正则表达式使用时的控制标记

    5 re.finditer

    re.finditer(pattern, string, flags=0) 选项: patten: 正则表达式的字符串或原生子串表达式 string: 待匹配字符串 flags: 正则表达式使用时的控制标记

    6、re.sub

    re.sub(pattern, repl, string, count = 0, flags=0) 选项: patten: 正则表达式的字符串或原生子串表达式 repl: 替换匹配字符串的字符串 string: 待匹配字符串 count: 匹配的最大替换次数 flags: 正则表达式使用时的控制标记

    3)Re库的另一种等价用法

    regex = re.compile(pattern, flags = 0) 选项: patten: 正则表达式的字符串或原生子串表达式 flags: 正则表达式使用时的控制标记 函数说明regex.search()在一个字符串中搜索匹配正则表达式的第一个位置,返回一个match对象regex.match()从一个字符串的开始位置起匹配正则表达式,返回match对象regex.findall()搜索字符串,以列表类型返回全部能匹配的子串regex.split()将一个字符串按照正则表达式匹配结果进行分割,返回列表类型regex.finditer()搜索字符串,返回一个匹配结果的迭代对象,每个迭代对象都是match对象regex.sub()在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

    4)Re库的match对象

    Match对象的属性

    属性说明.string待匹配的文本.re匹配时使用的pattern对象(正则表达式).pos正则表达式搜索文本的开始位置.endpos正则表达式搜索文本的结束位置

    Match对象的方法

    方法说明.group(0)获得匹配后的字符串.start()匹配字符串在原始字符串的开始位置.end()匹配字符串在原始字符串的结束位置.span()返回(.start(), .end())

    5)Re库的贪婪匹配和最小匹配

    Re库默认使用贪婪匹配,即输出匹配最长的子串。

    最小匹配操作符

    操作符说明*?前一个字符0次,或无限次扩展,最小匹配+?前一个字符1次,或无限次扩展,最小匹配??前一个字符0次,或1次扩展,最小匹配{m, n}?拓展前一个字符m至n次(含n),最小匹配

    单元六、Scrapy爬虫框架

    1)Scrapy爬虫框架解析

    各个模块说明:

    Engine——控制所有模块的数据流/根据条件触发事件【不需要用户修改】Downloader——根据请求下载网页【不需要用户修改】Scheduler——对所有爬取请求进行调度管理【不需要用户修改】Spiders——解析Downloader返回的响应(Response);产生爬取项(scraped item),产生额外的爬取请求(Request)【需要用户编写配置代码】Item Pipelines——以流水线方式处理Spider产生的爬取项;由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型;可能操作包括:清理、检验和查重爬取项中的HTML数据、将数据存储到数据库中。【需要用户编写配置代码】————————————————————————————————————Downloader Midderware——实施Engine、Scheduler和Downloader之间进行用户可配置的控制,可实现修改、丢弃、新增请求或响应【用户可编写配置代码】Spider Middleware——对请求和爬取项的再处理,可实现修改、丢弃、新增请求或爬取项【用户可编写配置代码】

    2)Scrapy爬虫的常用命令

    Scrapy是为持续运行设计的专业爬虫框架,提供操作的Scarpy命令行。

    命令说明格式startproject创建一个新工程scrapy startproject [dir]genspider创建一个爬虫scrapy genspider [options] settings获得爬虫配置信息scrapy settings [options]crawl运行一个爬虫scrapy crawl list列出工程中所有爬虫scrapy listshell启动URL调试命令行scrapy shell [url]

    3)scrapy 爬虫实例

    使用scrapy爬取页面:http://www.python123.io/ws/demo.html

    步骤:

    1 建立一个Scrapy爬虫工程

    生成的工程文件

    python123demo——》外层目录

    ​ scrapy.cfg——》部署Scrapy爬虫的配置文件

    ​ python123demo——》Scrapy框架的用户自定义Python代码

    ​ __ init __.py——》初始化脚本

    ​ items.py——》Items代码模块(继承类)

    ​ middlewares.py——》Middlewares代码模板(继承类)

    ​ pipelines.py——》Pipelines代码模板(继承类)

    ​ settings.py——》Scrapy爬虫的配置文件

    ​ spiders/——》Spriders代码模板目录(继承类)

    ​ __ init __.py——》初始文件,无需修改

    ​ __ pycache __/——》缓存目录,无需修改

    2 在工程中产生一个Scrapy爬虫(创建了一个py脚本存放在spiders目录下)

    在spiders目录下产生一个demo.py文件,查看文件:

    ​ 这里的parse()用于处理响应,解析内容形成字典,发现新的URL爬取请求。

    3 配置产生的spider爬虫

    4 运行爬虫,获取网页

    demo.py两个等价版本的区别

    yield关键字:

    yield 《——》生成器:不断产生值的函数

    生成器每次产生一个值(yield语句),就会被冻结,被唤醒后再从上次的位置继续再产生一个值。

    4)Scrapy爬虫的基本使用

    Scrapy爬虫的使用步骤:

    步骤一:创建一个工程和Spider模板 步骤二:编写Spider 步骤三:编写Item Pipeline 步骤四:优化配置策略

    Scrapy爬虫的数据类型:

    Request类 Response类 Item类

    Request类 class.Scrapy.http.Request()

    Request对象表示一个HTTP请求。由Spider生成,由Downloader执行 属性说明.urlRequest对应的请求URL地址.method对应的请求方法,‘GET’‘POST’等.headers字典类型风格的请求头.body请求内容主体,字符串类型.meta用户添加的拓展信息,在Scrapy内部模块间传递信息使用.copy()复制该请求

    Response类 class.Scrapy.http.Response()

    Response对象表示一个HTTP响应。由Downloader成,由Spider处理 属性或方法说明.urlResponse对应的URL地址.statusHTTP状态码,默认200.headersResponse对应的头部信息.bodyResponse对应的内容信息,字符串类型.flags一组标记.request产生Response类型的Request对象.copy复制该响应

    Item类 class.scrapy.item.item()

    Item对象表示一个从HTML页面中提取的信息内容由Spider生成,由Item Pipeline处理Item类似字典类型,可以按照字典类型操作

    5)Scrapy爬虫提取信息的方法

    Scrapy爬虫支持多种HTML信息提取方法:

    Beautiful SouplxmlreXPath SelectorCSS Selector

    CSS Selector的基本使用

    <html>.css('a::attr=(href)').extract() 获得对应的标签信息 注: a:标签名称 href:标签属性

    6)配置并发连接选项—settting.py文件

    选项说明CONCURRENT_REQUESTSDownloader最大并发下载数量,默认32CONCURRENT_ITEMSItem Pipeline最大并发ITEM处理数量,默认100CONCURRENT_REQUESTS_PRE_DOMAIN每个目标域名最大的并发请求数,默认8CONCURRENT_REQUESTS_PER_IO每个目标IP最大的并发请求数,默认为0,非0有效

    参考资料: 【1】Mooc - Python爬虫与信息提取

    Processed: 0.013, SQL: 9