MOOC《Python网络爬虫和信息提取》(第11次)网络爬虫之实战(第3周)

MOOC–Python网络爬虫和信息提取(第11次开课)

网络爬虫之实战 21.08.03

目录

测验3: Python网络爬虫之提取 (第3周)

1、以下不是正则表达式优势的选项是:‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、简洁

B、特征表达

C、实现自动化脚本

D、一行胜千言

正确答案 C

尽管正则表达式可用于自动化脚本,但不直接体现自动脚本的作用。

2、正则表达式:^ [A-Za-z\d]+$的含义是什么?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、由26个字母和数字组成的字符串

B、一个26个字母构成的字符串

C、由26个字母和特殊字符d组成的字符串

D、由26个字母组成的字符串

正确答案 A

以下这些操作符是正则表达式中最常用的:

在这里插入图片描述
在这里插入图片描述

3、正则表达式:\d{3}-\d{8}|\d{4}-\d{7}能匹配哪个?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、010-12345678

B、01012345678

C、010-1234567

D、0521-12345678

正确答案 A

\d{3}-\d{8}|\d{4}-\d{7}

表示:3个数字-8个数字 或者 4个数字-7个数字

4、re库可以使用如下方式表示正则表达式:r’[1-9]\d{5}’,其中r是什么意思?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、开始位置标记

B、正则表达式标记

C、强制标记

D、原生字符串标记

正确答案 D

字符串包括:普通字符串和原生字符串,原生字符串中没有转义符(\)。

5、正则表达式:^ [A-Za-z]+$的含义是什么?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、由字母a和z、A和Z组成的字符串

B、由26个字母和特殊字符d组成的字符串

C、由26个字母和数字组成的字符串

D、由26个字母组成的字符串

正确答案 D

6、正则表达式:^-?\d+$的含义是什么?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、一个整数形式的字符串

B、由26个字母和数字组成的字符串

C、一个带有负号的数字字符串

D、由26个字母组成的字符串

正确答案 A

7、正则表达式:1[1-9][0-9]$的含义是什么?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、整数形式的字符串

B、正整数形式的字符串

C、由0到9数字组成的字符串

D、数字和*组成的字符串

正确答案 B

8、正则表达式:[1-9]\d{5}的含义是什么?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、长度为5的正整数形式字符串

B、由0到9数字组成的字符串

C、整数形式的字符串

D、首位不为0的6长度数字形式字符串

正确答案 D

9、正则表达式:[\u4e00-\u9fa5]的含义是什么?‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、一个在\u4e00到\u9fa5之间的字符

B、由\u4e00到\u9fa5中一个或多个字符组成的字符串

C、由\u4e00到\u9fa5字符组成的字符串

D、\u4e00或\u9fa5

正确答案 A

10、Beautiful Soup库与re库之间关系,描述正确的是:‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

A、这两个库没有关系

B、re库能实现HTML解析,功能上与Beautiful Soup库类似

C、Beautiful Soup库中可以加载re库

D、re库中可以加载Beautiful Soup库

正确答案 A

两者没关系,re库以字符串模式匹配与检索方式提取信息,与Beautiful Soup库不同。

单元7:Re(正则表达式)库入门

7.1 正则表达式的概念

正则表达式是用来简洁表达一组字符串的表达式

应用:

  • 表达文本类型的特征
  • 查找或替换一组字符串
  • 匹配字符串的全部或部分(主要应用)

正则表达式的使用:

编译:将符合正则表达式语法的字符串转换成正则表达式特征。

7.2 正则表达式的语法

正则表达式语法由字符和操作符构成

操作符说明实例
.表示任何单个字符
[ ]字符集,对单个字符给出取值范围[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)表示anc、def
\d数字,等价于[ 0-9 ]
\w单词字符,等价于[A-Za-z0-9_]

正则表达式的实例:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.3 Re库的基本使用

7.3.1 正则表达式的表示类型

raw string类型(原生字符串):r’text’,r’[1-9]\d{5}’

​ rawstring是不包含对转义符再次转义的字符串

string 类型:‘[1-9]\d’、‘\d{3}-\d{8}|\d{4}-\d{7}’

7.3.2 Re库主要功能函数

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

7.3.3 Re库主要功能函数(详解)

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

在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象

  • pattern :正则表达式的字符串或原生字符串表示
  • string :待匹配字符串
  • flags :正则表达式使用时的控制标记
常用标记说明
re.I re.IGNORECASE忽略正则表达式的大小写,[A-Z]能够匹配小写字符
re.M re.MULTINE正则表达式中的^操作符能够将给定字符串的每行当做匹配开始
re.S re.DOTALL正则表达式中的 . 操作能够匹配所有字符(默认仅匹配除换行符以外的所有字符)
# re.search()
import re
match = re.search(r'[1-9]\d{5}','BIT 100081')
if match:
    print(match.group(0))   # 100081

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

从一个字符串的开始位置起匹配正则表达式,返回match对象

  • pattern :正则表达式的字符串或原生字符串表示
  • string :待匹配字符串
  • flags :正则表达式使用时的控制标记
# re.match()
import re
match = re.match(r'[1-9]\d{5}','BIT 100081')
if match:
    print(match.group(0))   # 空

match2 = re.match(r'[1-9]\d{5}','100081 BIT')
if match2:
    print(match2.group(0))   # 100081

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

搜索字符串,以列表类型返回能匹配的子串

  • pattern :正则表达式的字符串或原生字符串表示
  • string :待匹配字符串
  • flags :正则表达式使用时的控制标记
# re.findall()
import re
ls = re.findall(r'[1-9]\d{5}','BIT 100081 TSU100084')
print(ls)   # ['100081', '100084']

re.split(pattern, string, maxsplit=0,flag=0)

将一个字符串按照正则表达式匹配结果进行分割,返回列表类型

  • pattern :正则表达式的字符串或原生字符串表示
  • string :待匹配字符串
  • maxsplit:最大分割数,剩余部分作为最后一个元素输出
  • flags :正则表达式使用时的控制标记
# re.split()
import re
print(re.split(r'[1-9]\d{5}', 'BIT 100081 TSU100084'))
# ['BIT ', ' TSU', '']
print(re.split(r'[1-9]\d{5}', 'BIT 100081 TSU100084', maxsplit=1))
# ['BIT ', ' TSU100084']

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

搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象

  • pattern :正则表达式的字符串或原生字符串表示
  • string :待匹配字符串
  • flags :正则表达式使用时的控制标记
# re.finditer()
import re
for m in re.finditer(r'[1-9]\d{5}', 'BIT 100081 TSU100084'):
    if m:
        print(m.group(0))
# 100081
# 100084

re.sub(pattern, repl, string, count=0, flags=0)

在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

  • pattern :正则表达式的字符串或原生字符串表示
  • string :待匹配字符串
  • flags :正则表达式使用时的控制标记
# re.sub()
import re
print(re.sub(r'[1-9]\d{5}', ':zipcode', 'BIT 100081 TSU100084'))
# BIT :zipcode TSU:zipcode
print(re.sub(r'[1-9]\d{5}', ':zipcode', 'BIT 100081 TSU100084', count=1))
# BIT :zipcode TSU100084

7.3.4 Re库的等价用法

regex = re.compile(pattern, falgs=0)

将正则表达式的字符串编译成正则表达式对象

函数式用法:一次性操作

rst = re.search(r’[1-9]\d{5}’,‘BIT 100081’)

面向对象用法:编译后的多次操作

pat = re.compiler(r’[1-9]\d{5}’)

rest = pat.search(‘BIT 100081’)

7.4 Re库的match对象

Match对象是一次匹配的结果,包含匹配的很多信息

type(match) # <class ‘re.Match’>

7.4.1 Match对象的属性

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

7.4.1 Match对象的方法

方法说明
.group(0)获得匹配后的字符串
.start()匹配字符串在元氏字符串的开始位置
.end()匹配字符串在原始字符串的结束位置
.span()返回(.start(),end())
import re
m = re.search(r'[1-9]\d{5}', 'BIT100081 TSU100084')
print('m.string : {}\nm.re     : {}\nm.pos    : {}\nm.endpos : {}\n'.format(m.string,m.re,m.pos,m.endpos))
print('m.group(0) : {}\nm.start()  : {}\nm.end()    : {}\nm.span     : {}\n'.format(m.group(0),m.start(),m.end(),m.span()))
# 输出结果:
# m.string : BIT100081 TSU100084
# m.re     : re.compile('[1-9]\\d{5}')
# m.pos    : 0
# m.endpos : 19
 
# m.group(0) : 100081
# m.start()  : 3
# m.end()    : 9
# m.span     : (3, 9)

7.5 Re库的贪婪匹配和最小匹配

贪婪匹配:

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

最小匹配:

输出匹配最短的子串,可以通过在操作符后增加?变成最小匹配

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

单元8:实例2:淘宝商品比价定向爬虫

参考课程内容,只能爬取到淘宝的登录界面(淘宝的反爬虫机制),因而需要对访问的头文件做修改。

登录自己的淘宝账户,搜索如 书包 等相应商品,在搜索结果界面按F12打开开发者模式(本人用的chrome浏览器),一般浏览器右键源代码/检查也可

在这里插入图片描述

按照上图所示,可在网络Network中找到cookie内容,随后在代码的getHTMLText中添加cooki和user-agent(一般是Mozilla/5.0)即可

注意:有时需要对网页进行刷新才会出现该Name

整个过程即将自己账户的登录信息复制给头文件

在这里插入图片描述

# 参考代码
import requests
import re

def getHTMLText(url):
    kv={'cookie':'需填入自己的cooike内容'
        ,'user-agent':'Mozilla/5.0'}
    try:
        r = requests.get(url, headers = kv,timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""


def parsePage(ilt, html):
    try:
        # 注:pycharm编译下双引号、冒号等前无需加 \
        plt = re.findall(r'"view_price":"[\d.]*"',html)
        tlt = re.findall(r'"raw_title":".*?"',html)
        for i in range(len(plt)):
            price = eval(plt[i].split(':')[1])
            title = eval(tlt[i].split(':')[1])
            ilt.append([price , title])
    except:
        print("")

def printGoodsList(ilt):
    tplt = "{:4}\t{:8}\t{:16}"
    print(tplt.format("序号", "价格", "商品名称"))
    count = 0
    for g in ilt:
        count = count + 1
        print(tplt.format(count, g[0], g[1]))


def main():
    goods = '单片机'
    depth = 3
    start_url = 'https://s.taobao.com/search?q=' + goods
    infoList = []
    for i in range(depth):
        try:
            url = start_url + '&s=' + str(54 * i)
            html = getHTMLText(url)
            parsePage(infoList, html)
        except:
            continue
    printGoodsList(infoList)

main()

单元9:实例3:股票数据定向爬虫

这里采用 证券之星网 获取股票列表,用 网易财经网 获取单股数据。

import requests
from bs4 import BeautifulSoup
import re


def getHTMLText(url,code='utf-8'):
    kv = {'user-agent': 'Mozilla/5.0'}
    try:
        r = requests.get(url,headers = kv,timeout=30)
        r.raise_for_status()
        r.encoding = code
        return r.text
    except:
        return ""


def getStockList(lst, stockURL):
    html = getHTMLText(stockURL,'GB2312')
    soup = BeautifulSoup(html, 'html.parser')
    a = soup.find_all('span')
    for i in a:
        try:
            href = i.contents[0].attrs['href']
            lst.append(re.findall(r"\d{6}", href)[0])
        except:
            continue


def getStockInfo(lst, stockURL, fpath):
    count = 0
    for stock in lst:
        url = stockURL + '0'+ stock + ".html"
        html = getHTMLText(url)
        try:
            if html == "":
                continue
            infoDict = {}
            soup = BeautifulSoup(html, 'html.parser')

            # 网易财经单股使用数据文本形式保存,可以通过列表形式打印
            # name,code,price,change,yesteday,today,high,low
            
            div = soup.body.find('div', attrs={'class': 'relate_stock clearfix'})
            stockInfo = div('script')[0].string.strip().split(',')

            infoDict['股票名称'] = eval(re.search(r'name: \'.*\'', stockInfo[0]).group(0).split(':')[1])
            infoDict['股票代码'] = eval(re.search(r'code: \'\d{6}\'', stockInfo[1]).group(0).split(":")[1])
            infoDict['现价'] = eval(re.search(r'price: \'.*\'', stockInfo[2]).group(0).split(":")[1])
            infoDict['涨跌幅'] = re.search(r'change: \'.*%', stockInfo[3]).group(0).split("'")[1]
            infoDict['昨收'] = eval(re.search(r'yesteday: \'.*\'', stockInfo[4]).group(0).split(":")[1])
            infoDict['今开'] = eval(re.search(r'today: \'.*\'', stockInfo[5]).group(0).split(":")[1])
            infoDict['最高'] = eval(re.search(r'high: \'.*\'', stockInfo[6]).group(0).split(":")[1])
            infoDict['最低'] = eval(re.search(r'low: \'.*\'', stockInfo[7]).group(0).split(":")[1])

            with open(fpath, 'a', encoding='utf-8') as f:
                f.write(str(infoDict) + '\n')
                count = count + 1
                print("\r当前进度: {:.2f}%".format(count * 100 / len(lst)), end="")
        except:
            count = count + 1
            print("\r当前进度: {:.2f}%".format(count * 100 / len(lst)), end="")
            continue


def main():
    stock_list_url = 'http://quote.stockstar.com/stock/stock_index.htm'
    stock_info_url = 'http://quotes.money.163.com/'

    output_file = 'BaiduStockInfo.txt'
    slist = []
    getStockList(slist, stock_list_url)
    getStockInfo(slist, stock_info_url, output_file)


main()

资料来源:

Python网络爬虫与信息提取_北京理工大学_中国大学MOOC(慕课) https://www.icourse163.org/course/BIT-1001870001


  1. 0-9 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值