爬虫基础(笔记)——2.正则表达式、Xpath与BeautifulSoup

目录

正则表达式

正则表达式对象

正则表达式函数

1.re.match(pattern, string, flags=0模式修正符)

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

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

4.re.compile(pattern,flags=0)

5.re.split(pattern, string ,maxsplit=0分隔次数,不限制次数,flags=0)

6.re.sub(pattern, repl替换的字符串,也可为一个函数, string, count=0模式匹配后替换的最大次数,默认 0 表示替换所有的匹配,flags=0)

贪婪模式(默认)与懒惰模式

xpath

表达式

谓语

选取未知节点

选取若干路径

XPath 运算符

bs4  BeautifulSoup

根据标签名查找

获取属性

获取文本

find()方法

find_all方法

select方法


正则表达式

  • 正则表达式对象

  1. group() 返回被re匹配的字符串
  2. start() 返回匹配开始的位置
  3. end() 返回匹配结束的位置
  4. span() 返回一个元组包含匹配 (开始,结束) 的位置

 

  • 正则表达式函数

1.re.match(pattern, string, flags=0模式修正符)

尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,返回none;匹配成功,返回第一个匹配的对象。

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

搜索整个字符串,尝试从字符串的任意位置匹配,并返回第一个成功的匹配。

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

搜索整个字符串,返回一个list(所有匹配的对象)

1、当给出的正则表达式带有多个括号时,返回的列表中的元素为多个字符串组成的元组,元组中的元素个数与正则表达式所带的括号数目相同,字符串内容与每个括号内的正则表达式相对应,并且排列的顺序跟括号出现的顺序一样。

2、当给出的正则表达式中带有一个括号时,列表元素为字符串,并与括号中的正则表达式相对应(不是整个正则表达式)。

3、当给出的正则表达式不带括号时,列表元素为字符串,与整个正正则表达式匹配。

分组记法       (?P<name>...)

表达式中的引用记法   (?P=name)

替换时的引用的记法   \g<name>

4.re.compile(pattern,flags=0)

用于编译正则表达式,生成一个正则表达式( Pattern )对象。供 match() 和 search() 这两个函数使用

5.re.split(pattern, string ,maxsplit=0分隔次数,不限制次数,flags=0)

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

6.re.sub(pattern, repl替换的字符串,也可为一个函数, string, count=0模式匹配后替换的最大次数,默认 0 表示替换所有的匹配,flags=0)

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

 

  • 贪婪模式(默认)与懒惰模式

在给出的限定符在后面加上一个问号?即可将贪婪模式转为懒惰模式

 

xpath

(该部分取自https://cuiqingcai.com/2621.html

       lxml是一款高性能的 Python HTML/XML 解析器

  • 表达式

nodename 选取此节点的所有子节点
/ 从根节点选取,或是元素与元素间的过渡
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性
text() 选取文本

 

  • 谓语

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

         实例 在下面的表格中,列出了带有谓语的一些路径表达式,以及表达式的结果:

/bookstore/book[1]

 

选取属于 bookstore 子元素的第一个 book 元素

/bookstore/book[last()]

 

选取属于 bookstore 子元素的最后一个 book 元素

/bookstore/book[last()-1]

 

选取属于 bookstore 子元素的倒数第二个 book 元素

/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00

 

  • 选取未知节点

        XPath 通配符可用来选取未知的 XML 元素。

* 匹配任何元素节点
@* 匹配任何属性节点
node() 匹配任何类型的节点

 

  • 选取若干路径


         通过在路径表达式中使用“|”运算符,可以选取若干个路径。

//book/title | //book/price

 

选取 book 元素的所有 title 和 price 元素

//title | //price

选取文档中的所有 title 和 price 元素。

 

 

/bookstore/book/title | //price

选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

 

  • XPath 运算符

| 计算两个节点集
+,-,* 加法,减法,乘法
div 除法
mod 计算除法的余数
\=,!=,<,<=,>,>= 等于,不等于,小于,小于或等于,大于,大于或等于
or,and 或,与

 

bs4  BeautifulSoup

(该部分取自 https://www.jianshu.com/p/26a3632796dd)

注意:bs4只能解析html格式的数据

1.把页面数据交给BeautifulSoup处理,生成bs对象

soup = BeautifulSoup(response.text, "html.parser", from_encoding = "...")

soup = BeautifulSoup(response.text, "lxml", from_encoding = "...")

2.从bs对象中查找数据

  • 根据标签名查找

soup.a    只能查找得到第一个符合要求的节点,是一个对象

  • 获取属性

soup.a.attrs    获取得到所有属性和值,是一个字典

soup.a.attrs['href']   获取指定的属性值            soup.a['href']   简写形式

soup.a.get("href")   获取指定的属性值

  • 获取文本

soup.a.string

soup.a.text

soup.a.get_text()

[注]如果标签里面还有标签,那么string获取就是空,而后两个获取的是纯文本内容

  • find()方法

返回的是第一个满足条件的标签元素,节点对象

soup.find('a')  查找得到第一个a

soup.find('a', class_='xxx')  查找得到class是xxx的第一个a

soup.find('a', attrs={'class','xxx'})  查找得到第一个class是xxx的a

  • find_all方法

返回的是所有满足条件的标签,一个列表,列表里面都是节点对象

soup.find_all('a')     找到所有a 

soup.find_all('a', limit=2)      提取符合要求的前两个a

soup.find_all(['a', 'li'])     查找得到所有的a和li

soup.find_all('a', class_='xxx')  查找得到所有class是xxx的a

soup.find_all('li', class_=re.compile(r'^xiao'))  查找所有的class以xiao开头的li标签

  • select方法

id选择器 #dudu

类选择器 .xixi

标签选择器 div a h1

 

补充:

str.strip(): 用来去除头尾字符、空白符(包括\n、\r、\t、' ',即:换行、回车、制表符、空格)

str.lstrip():用来去除开头字符、空白符(包括\n、\r、\t、' ',即:换行、回车、制表符、空格)

str.rstrip():用来去除结尾字符、空白符(包括\n、\r、\t、' ',即:换行、回车、制表符、空格)

#爬取51job求职网 保存到数据库

import urllib.request
from bs4 import BeautifulSoup
import time
import pymysql

# 根据url生成请求对象
def handle_request(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
    }
    request = urllib.request.Request(url, headers=headers)
    return request

# 解析内容
def parse_content(content, db):
    # 生成soup对象
    soup = BeautifulSoup(content, 'lxml')
    # 先找包含所有工作的div
    odivbox = soup.find('div', id='resultList')
    # 首先找到包含所有工作的div
    odiv_list = odivbox.find_all('div', class_='el')[1:]
    # print(len(odiv_list))
    for odiv in odiv_list:
        # 职位名称
        jobname = odiv.select('.t1 > span > a')[0]['title']
        # 公司名称
        company = odiv.select('.t2 > a')[0]['title']
        # 工作地点
        area = odiv.select('.t3')[0].string
        # 职位月薪
        salary = odiv.select('.t4')[0].string
        # 发布时间
        publish_time = odiv.select('.t5')[0].string
        # print(salary, publish_time)
        # 保存到字典中
        item = {
            '职位名称': jobname,
            '公司名称': company,
            '工作地点': area,
            '职位月薪': salary,
            '发布时间': publish_time
        }
        # 保存到文件中
        # string = str(item) + '\n'
        # fp.write(string)

        # 保存到mysql中
        save_to_mysql(db, item)

def save_to_mysql(db, item):
    # 获取游标
    cur = db.cursor()
    # 执行sql语句
    sql = """insert into work(jobname,company,area,salary,publish_time) values('%s','%s','%s','%s','%s')""" % (item['职位名称'], item['公司名称'], item['工作地点'], item['职位月薪'], item['发布时间'])
    # print(sql)
    try:
        cur.execute(sql)
        #提交
        db.commit()
    except Exception as e:
        # print(e)
        #错误回滚
        db.rollback()

def main():
    # fp = open('work.txt', 'w', encoding='utf8')
    # 链接数据库
    db = pymysql.connect(host="localhost", user="root", password="123456", db="qiangge", port=3306, charset='utf8')
    # 用户输入要搜索工作关键字
    keyword = input('请输入要搜索的关键字-')
    # 用户输入要爬取的起始和结束页码
    start_page = int(input('请输入要爬取的起始页码-'))
    end_page = int(input('请输入要爬取的结束页码-'))
    # 要拼接的起始url
    url = 'https://search.51job.com/list/010000,000000,0000,00,9,99,{},2,{}.html'
    # 写循环,每一页开始挨着爬取
    for page in range(start_page, end_page + 1):
        print('正在爬取第%s页......' % page)
        # 拼接url
        url_page = url.format(keyword, page)
        # print(url_page)
        # 构建请求对象
        request = handle_request(url_page)
        # 发送请求,得到响应
        content = urllib.request.urlopen(request).read().decode('gbk')
        # 解析内容
        parse_content(content, db)
        print('结束爬取第%s页' % page)
        time.sleep(2)
    # fp.close()
    db.close()

if __name__ == '__main__':
    main()

 

上一篇:python爬虫基础(二)---0基础也能看得懂


下一篇:Beautiful Soup报错处理