Python爬虫三种解析方式,Pyhton360搜索排名查询

python爬虫中有三种解析网页的方式,正则表达式,bs4以及xpath,比较受用户喜爱的是bs4以及xpath,后期使用频率较高的是xpath,因为Scrapy框架默认使用的就是xpath解析网页数据。


数据解析方式  

  - 正则

  - xpath

  - bs4


正则 数据解析的原理:

标签的定位

提取标签中存储的文本数据或者标签属性中存储的数据


bs4解析

解析原理:

实例化一个Beautifulsoup的对象,且将页面源码数据加载到该对象中

使用该对象的相关属性和方法实现标签定位和数据提取


环境的安装:

pip install bs4
pip install lxml


实例化Beautifulsoup对象

BeautifulSoup(page_text,'lxml'):将从互联网上请求到的页面源码数据加载到该对象中

BeautifulSoup(fp,'lxml'):将本地存储的一样页面源码数据加载到该对象中


属性

soup.a.attrs 返回一字典,里面是所有属性和值

soup.a['href'] 获取href属性


文本

soup.a.string

soup.a.text

soup.a.get_text()


xpath解析:

- 解析效率比较高

- 通用性最强的


- 环境安装:pip install lxml

- 解析原理:

    - 实例化一个etree对象且将即将被解析的页面源码数据加载到该对象中

    - 使用etree对象中的xpath方法结合着xpath表达式进行标签定位和数据提取

- 实例化etree对象

    - etree.parse('本地文件路径')

    - etree.HTML(page_text)


在网页数据解析当中,re正则解析是比较费劲的,而且非常容易出错,网页数据结构一旦出错,则容易报出异常,而且想要匹配好正则,你的正则表达式需要熟练,不然你得一步步去尝试了,某些网页数据解析还真的只能用正则表达式去匹配。


如果你有接触过火车头采集器,那么对于正则,应该不会陌生!


实例的方式为大家展示Python爬虫三种解析方式


Pyhton360搜索排名查询

pic_001.jpg

关于搜索排名的结果查询,前面有分享过Python百度的搜索排名查询

网站百度排名查询,Python百度关键词搜索排名查询工具


360搜索排名查询,大同小异,比较烦人的就是协议头的处理

#构建协议头
def ua():
    ua=UserAgent()
    headers={
        'Cookie': 'QiHooGUID=622250714BFE7FEEBC7BE97B1768B7F1.1578470720454; _S=ilmjtet5usmi3a5005tq7of442; opqopq=d8a79fec6212514efe440041e132813c.1578470720',
        'Referer': 'https://www.so.com/haosou.html',
        "User-Agent":ua.random,
    }
    return headers

第一个就是ua,还有就是cookies,最后一个就是Referer的添加,这个在图片的反爬中比较常见!

协议头不对的反馈,相信你也会碰到!

pic_002.jpg

三种解析方式的处理,那就在细节上有小差异,同时还有部分数据的处理!


数据处理的关键点:

1.eval()函数

将str转为字典,提取排名


2.排名为空的情况

这里我用异常处理了

re正则的话写了 if else判断处理


3.xpath多个数据获取后的处理

title=''.join(li.xpath('.//a[1]//text()')[:-1]) #标题字符串处理

join函数以及切片的处理


bs4解析

#bs4获取数据
def get_bs4search(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        soup=BeautifulSoup(req,"html.parser")
        lis=soup.find("ul",class_="result").find_all("li",class_="res-list")
        print(len(lis))
        for li in lis:
            title=li.find("a").get_text()
            site_url=li.find("a")['href']
            try:
                pos=eval(li.find("a")['data-res'])['pos']  #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg=cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg !=[]:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('\n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")

find以及find_all方法

#find方法
#find只能找到符合要求的第一个标签,他返回的是一个对象
soup.find('a')
soup.find('a', class_='xxx')
soup.find('a', title='xxx')
soup.find('a', id='xxx')
soup.find('a', id=re.compile(r'xxx'))

#find_all
#返回一个列表,列表里面是所有的符合要求的对象
soup.find_all('a')
soup.find_all('a', class_='wang')
soup.find_all('a', id=re.compile(r'xxx'))
soup.find_all('a', limit=2)   #提取出前两个符合要求的a

当然还有个select方法,这里我没有用,可自行采用了解!

#选择,选择器 css中 


常用的选择器 

标签选择器、id选择器、类选择器 层级选择器** 

div h1 a 后面的是前面的子节点即可 

div > h1 > a 后面的必须是前面的直接子节点 

属性选择器 input[name='hehe'] select('选择器的') 返回的是一个列表,

列表里面都是对象 find find_all select不仅适用于soup对象,

还适用于其他的子对象,

如果调用子对象的select方法,

那么就是从这个子对象里面去找符合这个选择器的标签。


xpath解析

#xpath获取数据
def get_xmlsearch(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        html=etree.HTML(req)
        lis=html.xpath('//ul[@class="result"]/li[@class="res-list"]')
        for li in lis:
            title=''.join(li.xpath('.//a[1]//text()')[:-1]) #标题字符串处理
            site_url=li.xpath('.//a[1]/@href')[0]
            try:
                pos=eval(li.xpath('.//a[1]/@data-res')[0])['pos']   #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('\n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")


re正则解析

#re正则获取数据
def get_research(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        ul=re.findall(r'<ul class="result">(.+?)<div id="side">',req,re.S)[0]
        lis=re.findall(r'<li class="res-list"(.+?)</li>',ul,re.S)
        for li in lis:
            title=re.findall(r'<a href=".+?>(.+?)</a>',li,re.S)[0]
            title=title.replace('<em>','').replace('</em>','') #标题字符串处理
            site_url=re.findall(r'<a href="(.+?)".+?>.+?</a>',li,re.S)[0]
            if "data-res" in li:
                pos=re.findall(r',"pos":(.+?),"m":',li,re.S)[0]
                pm = (i - 1) * 10 + int(pos)
            else:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('\n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")

运行效果:

pic_003.gif

测试就找到一个作弊站。。

pic_004.jpg

附完整源码:

#360搜索排名查询
#20200108 by 微信:huguo00289
# -*- coding: utf-8 -*-

import requests,re,time
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
from lxml import etree


#构建协议头
def ua():
    ua=UserAgent()
    headers={
        'Cookie': 'QiHooGUID=622250714BFE7FEEBC7BE97B1768B7F1.1578470720454; _S=ilmjtet5usmi3a5005tq7of442; opqopq=d8a79fec6212514efe440041e132813c.1578470720',
        'Referer': 'https://www.so.com/haosou.html',
        "User-Agent":ua.random,
    }
    return headers

#获取访问数据
def get_html(url):
    response=requests.get(url,headers=ua(),timeout=10)
    print(response.status_code)
    req=response.content.decode('utf-8')
    return req

#获取搜索结果
#bs4获取数据
def get_bs4search(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        soup=BeautifulSoup(req,"html.parser")
        lis=soup.find("ul",class_="result").find_all("li",class_="res-list")
        print(len(lis))
        for li in lis:
            title=li.find("a").get_text()
            site_url=li.find("a")['href']
            try:
                pos=eval(li.find("a")['data-res'])['pos']  #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg=cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg !=[]:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('\n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")


#xpath获取数据
def get_xmlsearch(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        html=etree.HTML(req)
        lis=html.xpath('//ul[@class="result"]/li[@class="res-list"]')
        for li in lis:
            title=''.join(li.xpath('.//a[1]//text()')[:-1]) #标题字符串处理
            site_url=li.xpath('.//a[1]/@href')[0]
            try:
                pos=eval(li.xpath('.//a[1]/@data-res')[0])['pos']   #eval()函数,将str转为字典,提取排名
                pm=(i-1)*10+pos
            except:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('\n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")



#re正则获取数据
def get_research(keyword,num,cxurl):
    jg = []
    for i in range(1,int(num)+1):
        print(f'正在查询{i}页排名...')
        url="https://www.so.com/s?q=%s&pn=%d" % (keyword,i)
        req=get_html(url)
        ul=re.findall(r'<ul class="result">(.+?)<div id="side">',req,re.S)[0]
        lis=re.findall(r'<li class="res-list"(.+?)</li>',ul,re.S)
        for li in lis:
            title=re.findall(r'<a href=".+?>(.+?)</a>',li,re.S)[0]
            title=title.replace('<em>','').replace('</em>','') #标题字符串处理
            site_url=re.findall(r'<a href="(.+?)".+?>.+?</a>',li,re.S)[0]
            if "data-res" in li:
                pos=re.findall(r',"pos":(.+?),"m":',li,re.S)[0]
                pm = (i - 1) * 10 + int(pos)
            else:
                pm="空"
            print(pm,title,site_url)
            cxjg = cxwz(keyword, i, pm, title, site_url, cxurl)
            if cxjg != []:
                jg.append(cxjg)
        time.sleep(5)

    print("排名查询结果:")
    print("-----------------------------------------")
    if jg == []:
        print("该关键词无排名!")
    else:
        print('\n'.join(jg))
    print("-----------------------------------------")
    print("查询排名结束")


#查询网址是否存在排名
def cxwz(keyword,i,pm,title,site_url,cxurl):
    if cxurl in site_url:
        cxjg = f'关键词:{keyword},页码:第{i}页,排名:{pm},标题:{title},网址:{site_url}'
        print(f'关键词:{keyword},页码:第{i}页,排名:{pm},标题:{title},网址:{site_url}')
    else:
        cxjg=[]
    return cxjg


if __name__=="__main__":
    while True:
        keyword = input('请输入要查询的关键词:')
        num = input('请输入要查询的页码数:')
        url = input('请输入要查询的主域名:')
        try:
            get_bs4search(keyword,num,url)
        except IndexError as e:
            print(e)
            print("查询排名失败!")

感兴趣的话,不妨可以尝试重写百度搜索查询或者搜狗搜索查询!

当然神马的移动搜索查询也等着试试哦!