功能篇之爬虫

requests模块的cookie与session

正则、xpath、beautifulsoop

单线程+异步协程实现高性能爬虫

中文乱码问题处理

超级鹰实现12306模拟登陆

图片懒加载技术、selenium和PhantomJS

爬虫框架scrapy相关

一、requests模块的cookie与session

#基于cookie的案例分析:https://xueqiu.com/
import requests
from lxml import etree
import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
#自动获取cookie,cookie就会自动存储到session中
session = requests.Session()
session.get('https://xueqiu.com/',headers=headers)

#捕获ajax数据包获取的url
url = 'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=-1&count=10&category=-1'
#携带cookie进行的请求发送
dic_json = session.get(url=url,headers=headers).json()
print(dic_json)

二、正则、xpath、beautifulsoop

 

爬虫中正则的使用

def detail_parse(self, response):
    news_text=response.text
    content_list=re.findall('"digest":"(.*?)"',news_text)
detail_page_text = requests.get(url=detail_url,headers=headers).text
video_url = re.findall(ex,detail_page_text,re.S)[0]
for k,div in enumerate(div_list):
    title=re.findall('<a class=\"title_wl\".*?>(.*?)</a>',page_text)[k]

爬虫中xpath的使用

复制代码
1.下载:pip install lxml
2.导包:from lxml import etree

3.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点

  2.1 本地文件:tree = etree.parse(文件名)
                tree.xpath("xpath表达式")

  2.2 网络数据:tree = etree.HTML(网页内容字符串)
                tree.xpath("xpath表达式")
4.注意xpath匹配的对象均以列表的形式返回
复制代码

 

复制代码
def title_parse(self, response):
    detailnews_div_list = response.xpath('//div[@class="ndi_main"]/div')
    for detailnews_div in detailnews_div_list[0:2]:
        title = detailnews_div.xpath('./div/div[1]/h3/a//text()').extract_first()
        detailnews_url = detailnews_div.xpath('./div/div[1]/h3/a//@href').extract_first()
        item = WangyinewsallItem()
        item['title'] = title
        yield scrapy.Request(url=detailnews_url, callback=self.detail_parse, meta={'item': item})
复制代码
new_detail_url = div.xpath('./div/div[1]/h3/a/@href').extract_first()
li_list = response.xpath('//div[@class="ns_area list"]/ul/li')
VIEWSTATE_value=tree.xpath('//*[@id=\"__VIEWSTATE\"]/@value')[0]
from lxml import etree
page_text = requests.get(url=url,headers=headers,proxies={'http':'116.228.233.90:8082'}).text
tree = etree.HTML(page_text)
code_img_url = tree.xpath('//*[@id=\"verifyPic_login\"]/@src')[0]

爬虫中beautifulsoop的使用

复制代码
#安装环境
pip install bs4
pip install lxml

#导入beautiful包
from bs4 import BeautifulSoup
#实例化一个BeautifulSoup对象
#本地加载:
    soup=BeautifulSoup(fp,'lxml')
#网络加载:
    soup=BeautifulSoup(page_text,'lxml'),其中page_text为响应对象
基础巩固:
    (1)根据标签名查找
        - soup.a   只能找到第一个符合要求的标签
    (2)获取属性
        - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
        - soup.a.attrs['href']   获取href属性
        - soup.a['href']   也可简写为这种形式
    (3)获取内容
        - soup.a.string
        - soup.a.text
        - soup.a.get_text()
       【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
    (4)find:找到第一个符合要求的标签
        - soup.find('a')  找到第一个符合要求的
        - soup.find('a', title="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)根据选择器选择指定的内容
               select:soup.select('#feng')
        - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
            - 层级选择器:
                div .dudu #lala .meme .xixi  下面好多级
                div > p > a > .lala          只能是下面一级
        【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
复制代码
复制代码
#爬取斗破苍穹网站的小说
import requests
import re
import json
import os
import time
from bs4 import BeautifulSoup
url="https://doupocangqiong1.com/486/37zw/list_1.html"
headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
page_text=requests.get(url=url,headers=headers).text
soup=BeautifulSoup(page_text,'lxml')
span_list=soup.find_all('span',class_='n')
with open('神道丹尊.txt','wt',encoding='utf-8')as f:    
    for span in span_list[0:1]:
        title=' '.join(span.a.string.split(' ')[1:])
        data_list=span.a['href'].split('/')
        cid=re.search('\d+',data_list[2]).group()
        data={
            "siteid":'69',
            "bid":data_list[1],
            "cid":cid
        }
        noval_url="https://doupocangqiong1.com/novelsearch/chapter/transcode.html"
        json_content=requests.post(url=noval_url,headers=headers,data=data).content
        init_content=json.loads(json_content).get('info','')
        content=init_content.replace('<br>\n<br>','')
        f.write(title+'\n\n')
        f.write(content)
复制代码
复制代码
soup.p.text
soup.p.string
soup.p.get_text()
soup.find_all('div')
soup.find('div',class_=\"song\").get_text()
soup.select('.song')
soup.select('.tang > ul > li')
复制代码
复制代码
标签定位:
    soup.标签名称:定位标签;如有多个,返回第一个符合的标签。
    soup.find(tagname,attrName="value"):基于属性定位实现的标签定位,语法格式'div',class_='song',关键字(只有class??)需要下划线,返回单个标签
    soup.find_all(tagname,attrName="value")返回列表
取数据:
    取文本
        soup.tagname.text 取得标签下所有的标签内容
        soup.tagname.get_text 取得标签下所有的标签内容
        soup.tagname.string 取得标签中直系的文本内容
    取属性
        soup.tagname['attrName']
select:使用选择器定位标签
    标签,类,id选择器:soup.select('.song')返回列表
    层级选择器:
        单层级:
            soup.select('.song>ul>li')
        多层级:
            soup.select('.song li')
复制代码

三、单线程+异步协程实现高性能爬虫

- event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足某些条件的时候,函数就会被循环执行。程序是按照设定的顺序从头执行到尾,运行的次数也是完全按照设定。当在编写异步程序时,必然其中有部分程序的运行耗时是比较久的,需要先让出当前程序的控制权,让其在背后运行,让另一部分的程序先运行起来。当背后运行的程序完成后,也需要及时通知主程序已经完成任务可以进行下一步操作,但这个过程所需的时间是不确定的,需要主程序不断的监听状态,一旦收到了任务完成的消息,就开始进行下一步。loop就是这个持续不断的监视器。
- coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。
- task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。
- future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。
- 另外我们还需要了解 async/await 关键字,它是从 Python 3.5 才出现的,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。
import aiohttp
import asyncio
#回调函数:解析响应数据
def callback(task):
    print('this is callback()')
    #获取响应数据
    page_text = task.result()
    print('在回调函数中,实现数据解析')
    
async def get_page(url):
    async with aiohttp.ClientSession() as session:
        async with await session.get(url=url) as response:
            page_text = await response.text() #read()  json()
#             print(page_text)
            return page_text
start = time.time()
urls = [
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom',
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    #给任务对象绑定回调函数用于解析响应数据
    task.add_done_callback(callback)
    tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)

四、中文乱码问题处理

1.encoding='utf-8'

 

response=requests.get(url=url,headers=headers)
response.encoding='utf-8'
page_text=response.text

 

2.使用更广的编码集

 

#示例1:
img_name = li.xpath('./a/b/text()')[0]
img_name = img_name.encode('iso-8859-1').decode('gbk')

#示例2:
title=t.encode('iso-8859-1').decode('GBK')

 

posted @ 2019-06-02 11:27  海予心  阅读(208)  评论(0编辑  收藏  举报