博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
爬虫 正则 bs4 xpath 中文乱码 管道符
阅读量:4945 次
发布时间:2019-06-11

本文共 13713 字,大约阅读时间需要 45 分钟。

爬虫的分类:通用:聚焦:数据解析增量式:监测http:客户端和服务器端进行数据交互的形式证书密钥加密:什么是证书?证书种包含的是经过数字签名的公钥反爬:robotsUA伪装请求载体的身份标识在headers种应用一个字典(请求头信息:UA)动态加载的数据如何处理动态请求参数:封装到一个字典中,字典需要作用到data或者params
  • 编码的流程
    • 指定url
    • 发起请求
    • 获取响应数据
    • 数据解析
    • 持久化存储
  • 数据解析的作用
    • 用于获取页面中局部的页面源码数据
  • 如何实现数据解析
    • 正则
    • bs4(独有)
    • xpath(最为通用)
    • pyquery
  • 数据解析的通用原理是什么?
    • 标签定位
    • 将标签中间存储的文本数据或者其属性值进行捕获

 

正则解析

  • 需求:爬取糗事百科中的图片数据
    • 确认了页面中没有动态加载数据的存在

#爬取糗事百科

# re正则匹配
import requests
import re
import os
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}

dirname="./qiutu"

# 创建文件夹
if not os.path.exists(dirname):
os.mkdir(dirname)

 

url="https://www.qiushibaike.com/imgrank/page/%d/"

for page in range(1,3):

print("开始下载第{}页图片".format(page))
#指定新的url
new_url=format(url%page)
#获得源码文本信息
page_text=requests.get(url=new_url,headers=headers).text
ex='<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
# 获取图片地址 注意re.S
img_src_list=re.findall(ex,page_text,re.S)
for img_src in img_src_list:
new_img_src='https:'+img_src
img_name=img_src.split("/")[-1]
img_path=dirname+"/"+img_name
img_text=requests.get(url=new_img_src,headers=headers).content
with open(img_path,"wb") as f:
f.write(img_text)
print(img_name,"下载完毕!")
# 方法2:
# from urllib import request
# request.urlretrieve(new_img_src,img_path)
# <div class="thumb">

# <a href="/article/121911520" target="_blank">

# <img src="//pic.qiushibaike.com/system/pictures/12191/121911520/medium/S4TSN79VOC3G0R83.jpg" alt="糗事#121911520" class="illustration" width="100%" height="auto">
# </a>
# </div

bs4解析

  • 环境的安装:
    • pip install bs4
    • pip install lxml
  • bs4解析原理
    • 实例化一个BeautifulSoup的对象,且将即将被解析的页面源码加载到该对象中
    • 使用该对象中的属性或者方法进行标签定位和数据提取
  • BeautifulSoup对象的实例化方式:lxml就是一款解析器
    • BeautifulSoup(fp,'lxml'):将本地存储的html文档加载到该对象中
    • BeautifulSoup(page_text,'lxml'):将互联网上获取的html源码加载到该对象中
from bs4 import BeautifulSoupimport lxmlfp=open("./bs.html",'r',encoding="utf-8")soup=BeautifulSoup(fp,"lxml")soup
# 标签定位# soup.tagName:返回的就是页面中第一次出现的tagName标签(返回的是一个单数)# soup.title# soup.div# find函数的用法:属性定位# soup.find('tagName',attrName='value')# 注意:返回的是单数soup.find('div',class_="song")# soup.find_all('tagName'):定位所有的tagName的标签# soup.find_all('tagName',attrName='value'):属性定位# 注意:返回值是列表# soup.find_all("div")# soup.find_all("div",class_="song")# select('选择器'):根据选择器进行标签定位且返回的是复数(列表)# 类选择器,id选择器,标签选择器,层级选择器# 层级选择器:>表示一个层级,空格表示多个层级# soup.select(".song > p")[0]# soup.select(".tang > ul > li")# soup.select(".tang li")# 取数据(属性值和标签中存储的文本数据)# text 和 string 的区别:#  string  获取的是标签中直系的文本内容#  text 获取标签中所有的文本内容# soup.p.string# soup.p.text# 取属性:# tag['attrName']# soup.select("div > a")[0]["href"]# for a in soup.select(".tang > ul > li > a"):#     print(a["href"])

 

使用流程:           - 导包:from bs4 import BeautifulSoup    - 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容        (1)转化本地文件:             - soup = BeautifulSoup(open('本地文件'), 'lxml')        (2)转化网络文件:             - soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')        (3)打印soup对象显示内容为html文件中的内容基础巩固:    (1)根据标签名查找        - soup.a   只能找到第一个符合要求的标签      - soup.div  只能找到第一个div标签    (2)获取属性        - soup.a.attrs  获取a所有的属性和属性值,返回一个字典        - soup.a.attrs['href']   获取href属性        - soup.a['href']   也可简写为这种形式    (3)获取内容        - soup.a.string   # string获取的是标签中直系的文本内容        - soup.a.text   # text获取的是当前标签下所有文本内容,包括子标签        - soup.a.get_text()       【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容    (4)find:找到第一个符合要求的标签        - soup.find('a')  找到第一个符合要求的        - soup.find('a', title="xxx")  获取title=xxx的第一个标签        - soup.find('a', alt="xxx")   h获取alt=xxx的第一个标签        - soup.find('a', class_="xxx")  ...        - soup.find('a', id="xxx")   ...    (5)find_all:找到所有符合要求的标签        - soup.find_all('a')        - soup.find_all(['a','b']) 找到所有的a和b标签        - soup.find_all('a', limit=2)  限制前两个    (6)根据选择器选择指定的内容               - soup.select('#tang')        - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器            - 层级选择器:                select(".tang li") #class=tang标签下面的所有li标签,包含所有层级                div > p > a > .lala   # 只能是下面一级        【注意】select选择器返回永远是列表,需要通过下标提取指定的对象          总结:层级选择器定位返回总是一个复数(列表) 类选择器,id选择器,标签选择器,层级选择器 层级选择器:>表示一个层级,空格表示多个层级

 

 

 

 

爬取三国演义小说 url = 'http://www.shicimingju.com/book/sanguoyanyi.html'page_text = requests.get(url=url,headers=headers).text#使用bs4进行数据解析(章节标题&内容)soup = BeautifulSoup(page_text,'lxml')a_list = soup.select('.book-mulu > ul > li > a')fp = open('sanguo.txt','w',encoding='utf-8')for a in a_list:    title = a.string    detail_url = 'http://www.shicimingju.com'+a['href']    #对详情页的url发起请求解析出章节内容    detail_page_text = requests.get(url=detail_url,headers=headers).text    detail_soup = BeautifulSoup(detail_page_text,'lxml')    content = detail_soup.find('div',class_='chapter_content').text        fp.write(title+':'+content+'\n')    print(title,'保存成功!!!')fp.close()

xpath

xpath解析

  • 环境安装:pip install lxml
  • 解析原理:
    • 实例化一个etree类型的对象,且将即将被解析的页面源码数据加载到该对象中
    • 调用该对象中的xpath方法结合着不同的xpath表达式进行标签定位和数据提取
  • 实例化对象:
    • etree.parse(fileName)
    • etree.HTML(page_text)
from lxml import etreetree=etree.parse('bs.html')# 属性定位# tree.xpath('//div[@class="song"]')# 索引定位# 索引值是从1开始# 在xpath表达式中非最左侧的/和//的区别?# /表示一个层级# //表示多个层级# tree.xpath("//div[@class='song']//text()")# 取文本# /text():获取的是标签下直系的文本数据# //text():获取的是标签下所有的文本数据# tree.xpath("//div[@class='song']/p[1]/text()")# tree.xpath("//div[@class='song']//a[1]/span/text()")# 取属性# tree.xpath("//div[@class='song']//img/@src")

 

基于标签定位:  tree.xpath('/html/head/meta')  tree.xpath('//meta')  xpath表达式中最左侧的/和//的区别是什么?/表示我们必须从根标签进行定位//表示我们可以从任意位置标签定位属性定位:    #找到class属性值为song的div标签    //div[@class="song"] 层级&索引定位:    #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a    //div[@class="tang"]/ul/li[2]/a  tree.xpath('//div[@class="tang"]/ul/li[3]')    tree.xpath('//div[@class="tang"]//li[3]') # 与上一条属性索取为相同结果  在xpath表达式中非最左侧的/和//的区别? /表示一个层级 //表示多个层级逻辑运算:    #找到href属性值为空且class属性值为du的a标签    //a[@href="" and @class="du"]模糊匹配:    //div[contains(@class, "ng")]    //div[starts-with(@class, "ta")]取文本:    # /表示获取某个标签下的文本内容    # //表示获取某个标签下的文本内容和所有子标签下的文本内容    //div[@class="song"]/p[1]/text()    //div[@class="tang"]//text()取属性:    //div[@class="tang"]//li[2]/a/@href

 

 

 

# 爬取boss中的岗位信息(岗位名称,薪资,公司名称,岗位描述)import requestsfrom lxml import etreeheaders={    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}url="https://www.zhipin.com/c101010100/?query=python后端&page=%d"fp=open("boss.txt","w",encoding="utf-8")for page in range(1,4):    new_url=format(url%page)    page_text=requests.get(url=new_url,headers=headers).text    tree=etree.HTML(page_text)#     获取工作列表    li_list=tree.xpath("//div[@class='job-box']/div[@class='job-list']/ul/li")        for li in li_list:        job_title=li.xpath("./div//h3[@class='name']/a/div[1]/text()")[0]        salary=li.xpath("./div//h3[@class='name']/a/span/text()")[0]        company=li.xpath("./div/div[2]/div/h3/a/text()")[0]        #         详细信息网页        detail_url='https://www.zhipin.com' + li.xpath('./div/div[1]/h3/a/@href')[0]        detail_text=requests.get(url=detail_url,headers=headers).text                detail_tree=etree.HTML(detail_text)        desc=detail_tree.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div/text()')        desc=''.join(desc)                        fp.write(job_title+":"+"\n"+salary+"\n"+company+"\n"+desc)fp.close()

 

# 处理中文乱码问题# url = 'http://pic.netbian.com/4kmeinv/index_%d.html'import requestsfrom lxml import etreeheaders={    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}fp=open('meinv.txt','w',encoding='utf-8')for page in range(1,4):    if page==1:        url="http://pic.netbian.com/4kmeinv/"    else:        url="http://pic.netbian.com/4kmeinv/index_{}.html".format(page)    response=requests.get(url=url,headers=headers)    #     解决中文乱码方式1  耗资源 不推荐#     response.encoding='gbk'    page_text=response.text        tree=etree.HTML(page_text)    li_list=tree.xpath('//*[@id="main"]/div[3]/ul/li')    for li in li_list:        img_name=li.xpath("./a/b/text()")[0]                #     解决中文乱码方式2        img_name=img_name.encode("iso-8859-1").decode("gbk")        img_url='http://pic.netbian.com' +  li.xpath('./a/img/@src')[0]        fp.write(img_name+":"+img_url+"\n")       fp.close()
# 增强xpath表达式的通用性  ****采用管道符# url="https://www.aqistudy.cn/historydata/"# 获取热门城市与普通城市的城市名  import requestsfrom lxml import etreeheaders={    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}url="https://www.aqistudy.cn/historydata/"response=requests.get(url=url,headers=headers)page_text=response.texttree=etree.HTML(page_text)# hot_city=tree.xpath('//div[@class="hot"]//div[@class="bottom"]/ul/li/a/text()')# print(hot_city)# all_city=tree.xpath('//div[@class="all"]//div[@class="bottom"]/ul/div[2]/li/a/text()')# print(all_city)# cities=tree.xpath('//div[@class="hot"]//div[@class="bottom"]/ul/li/a/text() | //div[@class="all"]//div[@class="bottom"]/ul/div[2]/li/a/text()')# print(cities)# cities=tree.xpath('//div[@class="all"]//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="hot"]//div[@class="bottom"]/ul/li/a/text()')# print(cities)

举例

# 糗事百科的段子内容和作者(xpath的管道符)名称进行爬取,然后存储到mysql中or文本import requestsfrom lxml import etreeimport osheaders={    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}dirName='./homework'if not os.path.exists(dirName):    os.mkdir(dirName)filepath=os.path.join(dirName,"qiubai.txt")            fp=open(filepath,'w',encoding="utf-8")# 指定urlurl='https://www.qiushibaike.com/text/page/%d/'for page in range(1,10):    print("开始下载第{}页".format(page))    new_url=format(url%page)        #     发送请求 获取数据    response=requests.get(url=new_url,headers=headers)    page_text=response.text    tree=etree.HTML(page_text)    info_list=tree.xpath('//div[@id="content-left"]/div')    for info in info_list:#         管道符号获取所有用户        user_name=info.xpath("./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()")[0]                content=info.xpath("./a[1]/div/span/text()")        content=''.join(content)        qiubai=user_name.strip()+":"+content.strip()+"\n\n"        fp.write(qiubai)fp.close()print("下载完毕!")
# http://sc.chinaz.com/jianli/free.html爬取简历模板import requestsfrom lxml import etreeimport osimport timeimport randomheaders={    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}dirName='./homework'if not os.path.exists(dirName):    os.mkdir(dirName)    for page in range(1,3):    if page==1:        url='http://sc.chinaz.com/jianli/free.html'    else:        url='http://sc.chinaz.com/jianli/free_{}.html'.format(page)        page_text=requests.get(url=url,headers=headers).text    tree=etree.HTML(page_text)    a_list=tree.xpath('//div[@id="container"]/div/a/@href')#     print(a_list)    for a in a_list:        detail_text=requests.get(url=a,headers=headers).text        detail_tree=etree.HTML(detail_text)        #         下载路径        a_detail=detail_tree.xpath('//*[@id="down"]/div[2]/ul/li[1]/a/@href')[0]#         print(a_detail)        filename=detail_tree.xpath('//div[@class="ppt_left fl"]//h1//text()')[0]    #     识别中文        filename1 = filename.encode("iso-8859-1").decode("utf-8")+'.rar'                print(filename1)                response=requests.get(url=a_detail,headers=headers)        file_content=response.content                filepath=os.path.join(dirName,filename1)        print(filepath)        with open(filepath,'wb') as f:            f.write(file_content)        time.sleep(random.randint(1,3))        print("ok1111111111111")print("ok")
开线程池# http://sc.chinaz.com/jianli/free.html爬取简历模板from concurrent.futures import ThreadPoolExecutorimport requestsfrom lxml import etreeimport osimport timeimport randomprint("start")start=time.time()headers = {    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'}dirName = './homework'if not os.path.exists(dirName):    os.mkdir(dirName)url_dic={}for page in range(1, 3):    if page == 1:        url = 'http://sc.chinaz.com/jianli/free.html'    else:        url = 'http://sc.chinaz.com/jianli/free_{}.html'.format(page)    page_text = requests.get(url=url, headers=headers).text    tree = etree.HTML(page_text)    a_list = tree.xpath('//div[@id="container"]/div/a/@href')    #     print(a_list)    for a in a_list:        detail_text = requests.get(url=a, headers=headers).text        detail_tree = etree.HTML(detail_text)        #         下载路径        a_detail = detail_tree.xpath('//*[@id="down"]/div[2]/ul/li[1]/a/@href')[0]        #         print(a_detail)        filename = detail_tree.xpath('//div[@class="ppt_left fl"]//h1//text()')[0]        #     识别中文        filename1 = filename.encode("iso-8859-1").decode("utf-8") + '.rar'        url_dic[filename1]=a_detail        # response = requests.get(url=a_detail, headers=headers)        # file_content = response.content        #        # filepath = os.path.join(dirName, filename1)        # # print(filepath)        # with open(filepath, 'wb') as f:        #     f.write(file_content)        # # time.sleep(random.randint(1, 3))print(url_dic)def get_html(name,url):    res=requests.get(url,headers=headers)    return {
"name":name,"content":res.content}def parser_page(ret_obj): dic=ret_obj.result() with open(dic['name'], 'wb') as f: f.write(dic['content'])t=ThreadPoolExecutor(30)for name in url_dic: task=t.submit(get_html,name,url_dic[name]) task.add_done_callback(parser_page)print("ok",time.time()-start)

 

转载于:https://www.cnblogs.com/XLHIT/p/11297463.html

你可能感兴趣的文章
水晶苍蝇拍:聊聊估值那些事儿——“指标”背后的故事 (2011-11-01 14:58:32)
查看>>
3.每周总结
查看>>
应用提交 App Store 上架被拒绝
查看>>
Android实现异步处理 -- HTTP请求
查看>>
数据清空js清空div里的数据问题
查看>>
Fortran中的指针使用
查看>>
移动终端app测试点总结
查看>>
14-6-27&28自学内容小结
查看>>
JSP
查看>>
---
查看>>
(第一组_GNS3)自反ACl
查看>>
hdu--1258--Sum It Up(Map水过)
查看>>
Spring @DeclareParents 的扩展应用实例
查看>>
VS2012更新Update1后帮助查看器无法打开
查看>>
Android 文件的读取和写入
查看>>
高校表白APP-冲刺第四天
查看>>
outlook 设置163邮箱
查看>>
mysql优化——show processlist命令详解
查看>>
Solr服务器搭建
查看>>
画世界怎么用光影_世界绘画经典教程:水彩光影魔法教程
查看>>