Python网络爬虫与信息提取——正则表达式
正则表达式的语法
| 
                   正则表达式的常用操作符  | 
              ||
| 操作符 | 说明 | 实例 | 
| 
                   .  | 
                表示任何单个字符 | 
                   
  | 
              
| 
                   []  | 
                字符集,对单个字符给出取值范围 | [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)表示abe, (abcldef)表示abe、 def | 
| 
                   \d  | 
                数字,等价于[0-9] | 
                   
  | 
              
| 
                   \w  | 
                单词字符,等价于[A-Za-z0-9_] | 
                   
  | 
              
Re库的基本使用
raw string类型(原生字符串类型)
1.用原生字符串类型不用专义,如r'\d+\w{3}'
2.不用原生字符串类型,如‘\\d+\\w{3}’
| 
                   Re库主要功能函数  | 
              |
| 函数 | 说明 | 
| re.search() | 在一个字符串中搜索匹配正则表达式的第一个位置, 返回match对象 | 
| re.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 | 
| re.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 | 
| re.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 | 
| re.finditer() | 搜索字符串,返回一个匹配结果的选代类型,每个迭代元素是match对象 | 
| re.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 | 
1.re.search(pattern, string, flags=0)
在一个字符串中搜索匹配正则表达式的第一个 位置,返回match对象。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆flags:正则表达式使用时的控制标记
| flags:正则表达式使用时的控制标记 | |
| 常用标记 | 说明 | 
| re.I re.IGNORECAS | 忽略正则表达式的大小写,[A-Z]能够匹配小写字符 | 
| re.M re.MULTILINE | 正则表达式中的^操作符能够将给定字符串的每行当作匹配开始 | 
| re.S re.DOTALL | 
                   正则表达式中的操作符能够匹配所有字符,默认匹配除换行外的所有字符  | 
              
            
              import re
match = re.search(r'[1-9]\d{5}','bat 100081')
if match:
    print match.group(0)   ##100081
            
          
          
2.re. match(pattern, string, flags=0)
从一个字符串的开始位置起匹配正则表达式,返回match对象。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆flags: 正则表达式使用时的控制标记
            
              import re
match = re.match(r'[1-9]\d{5}','bit 100081')
if match:
    print match.group(0)
match = re.match(r'[1-9]\d{5}','100081 bit')
if match:
    print match.group(0)  #100081
            
          
          3.re.findall(pattern, string, flags=0)
搜索字符串,以列表类型返回全部能匹配的子串。
◆pattern:正则表达式的字符串或原生字符串表示
◆string;待匹配字符串
◆flags:正则表达式使用时的控制标记
            
              ls = re.findall(r'[1-9]\d{5}','bit100081 tsu100084')
print ls   #['100081', '100084']
            
          
          4.re.split(pattern, string, maxsplit=0, flags=0)
将一个字符串按照正则表达式匹配结果进行分割,返回列表类型。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆maxsplit:最大分割数,剩余部分作为最后一个 元素输出
◆flags:正则表达式使用时的控制标记
            
              print re.split(r'[1-9]\d{5}','bit100081 tsu100084')
#['bit', ' tsu', '']
print re.split(r'[1-9]\d{5}','bit100081 tsu100084', maxsplit=1)
#['bit', ' tsu100084']
            
          
          
5.re.finditer(pattern, string, flags=0)
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象。
◆pattern:正则表达式的字符串或原生字符串表示
◆string:待匹配字符串
◆flags:正则表达式使用时的控制标记
            
              for m in re.finditer(r'[1-9]\d{5}','bit100081 tsu100084'):
    if m:
        print m.group(0)
#100081
#100084
            
          
          
6.re.sub(pattern, repl, string, count=0, flags=0)
在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串。
◆pattern: 正则表达式的字符串或原生字符串表示
◆repl:替换匹配字符串的字符串
◆string:待匹配字符串
◆count:匹配的最大替换次数
◆flags:正则表达式使用时的控制标记
            
              print re.sub(r'[1-9]\d{5}',':zipcode','bit100081 tsu100084')
#bit:zipcode tsu:zipcode
            
          
          Re库的另一种等价用法:
            
              pat = re.compile(r'[1-9]\d{5}')
res = pat.search('bit 100081')
regex = re.compile(pattern, flags=0)
            
          
          将正则表达式的字符串形式编译成正则表达式对象
◆pattern:正则表达式的字符串或原生字符串表示
◆flags:正则表达式使用时的控制标记
Re库的match对象
| 
                   match对象的属性  | 
              |
| 属性 | 说明 | 
| .string | 待匹配的文本 | 
| .re | 匹配时使用的pattern对象(正则表达式) | 
| .pos | 正则表达式搜索文本的开始位置 | 
| 
                   .endpos  | 
                正则表达式搜索文本的结束位置 | 
| Match对象的方法 | |
| 方法 | 说明 | 
| .group(0) | 获得匹配后的字符串 | 
| .start() | 匹配字符串在原始字符串的开始位置 | 
| .end() | 匹配字符串在原始字符串的结束位置 | 
| .span() | 返回(.start(), .end()) | 
            
              m = re.search(r'[1-9]\d{5}','bit100081 tsu100084')
print m.string  #bit100081 tsu100084
print m.re  #<_sre.SRE_Pattern object at 0x10854d7b0>
print m.pos  #0
print m.endpos   #19
print m.group(0)  #100081
print m.start()  #3
print m.end()   #9
print m.span()   #(3,9)
            
          
          
实例:淘宝商品信息定向爬虫
            
              def gethtmltext(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""
def parsepage(ilt, html):
    try:
        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:
        print tplt.format(count, g[0], g[1])
def main():
    goods = '书包'
    depth = 2
    start_url = 'https://s.taobao.com/search?q=' + goods
    infolist = []
    for i in range(depth):
        try:
            url = start_url + '&s=' + str(44+i)
            html = gethtmltext(url)
            parsepage(infolist, html)
        except:
            continue
    printgoodslist(infolist)
main()
实例:股票数据定向爬虫
def gethtmltext(url):
  try:
    r = requests.get(url, timeout=30)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    return r.text
  except:
    return ""
def getstocklist(lst, stockurl):
  html = gethtmltext(stockurl)
  soup = BeautifulSoup(html, 'html.parser')
  a = soup.find_all('a')
  for i in a:
    try:
      href = i.attrs['href']
      lst.append(re.findall(r"[s][hz]\d{6}", href))
    except:
      continue
def getstockinfo(lst, stockurl, fpath):
  for stock in lst:
    url = stockurl + stock + '.html'
    html = gethtmltext(url)
    try:
      if html == "":
        continue
      infodict = []
      soup = BeautifulSoup(html, 'html.parser')
      stockinfo = soup.find('div', attrs={'class':'stock-bets'})
      name = stockinfo.find_all(attrs={'class':'bets-name'})[0]
      infodict.update({'股票名称':name.text.split()[0]})
      keylist = stockinfo.find_all('dt')
      valuelist = stocklist.find_all('dd')
      for i in range(len(keylist)):
        key = keylist[i].text
        val = valuelist[i].text
        infodict[key] = val
      with open(fpath, 'a', encoding='utf-8') as f:
        f.write(str(infodict) + '\n')
def main():
  stock_list_url = 'http://quote.eastmoney.com/stocklist.html'
  stock_info_url = 'https://gupiao.baidu.com/stock'
  output_file = './baiduinfostock.txt'
  slist = []
  getstocklist(slist, stock_list_url)
  getstockinfo(slist, stock_info_url, output_file)
main()
            
          
          

