郭炜老师mooc第十二章网络爬虫设计

网络爬虫

示例:获取百度图片的搜索结果图片(用requests.get获取网页)

复制代码
# 示例:获取百度图片的搜索结果图片

import re
import requests #request库用于获取网络资源 pip install requests

# 用requests.get获取网页
def getHtml(url): #获取网址url的网页
    fakeHeaders = {'User-Agent': #用于伪装浏览器发送请求
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
    AppleWebKit/537.36 (KHTML, like Gecko) \ '
    'Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.416.77',
    'Accept': 'text/html,application/xhtml+xml,*/*'}
    try:
        r = requests.get(url,headers = fakeHeaders)
        r.encoding = r.apparent_encoding #确保网页编码正确
        return r.text #返回值是个字符串,内含整个网页内容
    except Exception as e:  #防止错误url
        print(e)
        return "" 
#用法:html = getHtml("http://openjudge.cn")

def getBaiduPictures(word, n):
#下载n个百度图片搜来的关于word的图片保存到本地
    url ="""https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1
    &fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=
    &face=0&istype=2&ie=utf-8&word="""

    url += word
    html = getHtml(url)
    pt = '\"thumbURL\":\"(.*?)\"' # 这个正则表达式也可以
    
#     pt = '\"thumbURL\":.*?\"(.*?)\"' #正则表达式,用于寻找图片网址
    i = 0
    #"thumbURL":"https://img1.baidu.com/it/u=716463119,473541077&fm=26&fmt=auto&gp=0.jpg",

    for x in re.findall(pt, html): #x就是图片url
        print(x)  
        x = x.lower()
        try:
            r = requests.get(x, stream=True)#获取x对应的网络资源
            f = open(r"D:\桌面\爬虫项目\{0}{1}.jpg".format(word,i), "wb")
            #"wb"表示二进制写方式打开文件
            f.write(r.content) #图片内容写入文件
            f.close()
            i = i + 1
        except Exception as e :
            pass
        if i >= n:
            break
    
getBaiduPictures("猫", 5)
getBaiduPictures("熊猫" , 5)

requests库获取网页的优势和局限:

pyppeteer的介绍

用pyppeteer获取网页

复制代码
# 示例:获取百度图片的搜索结果图片

import re
import requests #request库用于获取网络资源 pip install requests

import asyncio

import nest_asyncio
nest_asyncio.apply()
# 这两句代码是出现 RuntimeError: This event loop is already running 问题的解决方案

# 用pyppeteer获取网页
def getHtml(url): #暂时适用于百度图片搜索
    import pyppeteer as pyp
    async def asGetHtml(url): #获取url对应网页的源代码 
        browser = await pyp.launch(headless=False, executablePath = r"E:\Download_Softwear\chromium\chrome-win\chrome-win\chrome.exe")
        # 启动Chromium,browser即为Chromium浏览器,非隐藏启动
        '''
        launch的其它参数
        browser = await launch(headless=False,executablePath = "c:/tmp/chrome-win32/chrome.exe",
        userdataDir = "c:/tmp")
        excutablePath: 如果Chromium没有安装在默认文件夹下面,则需要指定其位置
        userdataDir: userdataDir指明用来存放浏览器工作期间存放临时文件的文件夹,
        不是必须,能够防止可能出现的莫名其妙的错误
        
        launch的英文释义是发射,这里是 指的启动个浏览器,这个函数是个异步函数,
        所以必须await ,不然是会报错的
        '''
        
        page = await browser.newPage()# 在浏览器中打开一个新页面(标签), 启动一个新的 选项卡页面
        await page.setUserAgent('Mozilla/5.0 (Windows NT 6.1; \
        Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \
        Chrome/78.0.3904.70 Safari/537.36') #反反爬措施
        '''
        修改终端:
        Puppeteer 提供了几个有用的方法让我们可以修改设备信息
        page.setViewport(viewport)
        page.setUserAgent(userAgent)
        '''
        
        await page.evaluateOnNewDocument(
        '() =>{ Object.defineProperties(navigator, \{ webdriver:{ get: () => false } }) }' ) #反反爬措施
        
        await page.goto(url) # 装入url对应的网页;前往一个页面
        text = await page.content() # page.coutent就是网页源代码字符串
        await browser.close() # 关闭浏览器
        return text
    #速度大约比用requests.get慢5,6倍
    
    m = asyncio.ensure_future(asGetHtml(url)) #协程外启动协程
    asyncio.get_event_loop().run_until_complete(m) #等待协程结束
    '''
    run_until_complete是一个阻塞调用,知道协程运行结束才返回;
    它的参数是一个future,但是我们传给它的却是协程对象,它在内部做了检查,通过ensure_future函数
    把协程对象包装成了future
    '''
    return m.result() #返回的就是asGetHtml的返回值 text


# 用requests.get获取网页
# def getHtml(url): #获取网址url的网页
#     fakeHeaders = {'User-Agent': #用于伪装浏览器发送请求
#     'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
#     AppleWebKit/537.36 (KHTML, like Gecko) \ '
#     'Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.416.77',
#     'Accept': 'text/html,application/xhtml+xml,*/*'}
#     try:
#         r = requests.get(url,headers = fakeHeaders)
#         r.encoding = r.apparent_encoding #确保网页编码正确
#         return r.text #返回值是个字符串,内含整个网页内容
#     except Exception as e:  #防止错误url
#         print(e)
#         return "" 
#用法:html = getHtml("http://openjudge.cn")

def getBaiduPictures(word, n):
#下载n个百度图片搜来的关于word的图片保存到本地
    url ="""https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1
    &fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=
    &face=0&istype=2&ie=utf-8&word="""

    url += word
    html = getHtml(url)
    pt = '\"thumbURL\":\"(.*?)\"' # 这个正则表达式也可以
    
#     pt = '\"thumbURL\":.*?\"(.*?)\"' #正则表达式,用于寻找图片网址
    i = 0
    #"thumbURL":"https://img1.baidu.com/it/u=716463119,473541077&fm=26&fmt=auto&gp=0.jpg",

    for x in re.findall(pt, html): #x就是图片url
        print(x)  
        x = x.lower()
        try:
            r = requests.get(x, stream=True)#获取x对应的网络资源
            f = open(r"D:\桌面\爬虫项目\{0}{1}.jpg".format(word,i), "wb")
            #"wb"表示二进制写方式打开文件
            f.write(r.content) #图片内容写入文件
            f.close()
            i = i + 1
        except Exception as e :
            pass
        if i >= n:
            break


getBaiduPictures("猫", 10)
getBaiduPictures("熊猫" , 15)

出现 RuntimeError: This event loop is already running 问题解决:
查阅博客后,发现所使用的 Python 编辑器为 Spyder,其连接着 IPython 内核,而 IPython 内核本身在事件循环上运行,而 asyncio 不允许嵌套其事件​​循环,因此会出现如上图的错误信息。
输入这两句代码即可:

复制代码
import nest_asyncio
nest_asyncio.apply()

pyppeteer最为核心类Page的接口方法

Page类选择器相关方法有5个,并且这五个都有别名,分别是:

J()别名querySelector()

JJ()别名querySelectorAll()

JJeval()别名querySelectorAllEval()

Jeval()别名querySelectorEval()

Jx()别名xpath()

协程函数 querySelector(selector:str)

获取匹配的元素的selector

参数:搜索元素的选择器字符串。

返回[ElementHandle]或者None。

协程函数 querySelectorAll(selector:str)

获取匹配的所有元素selector作为列表。

参数:搜索元素的选择器

返回列表或返回空列表。

协程函数 querySelectorAllEval(selector:str,pageFunction:str,*args)

对所有匹配元素执行js

参数:

selector(str)-选择器。

pageFunction(str)-要在浏览器上运行的JavaScript函数的字符串,此函数将匹配元素的数组作为第一个参数。

args(Any)-传递给pageFunction的其他参数。

协程函数 querySelectorEval(selector:str,pageFunction:str,*args)

对匹配的元素执行js函数

参数:

selector(str)-定位的选择器字符串。

pageFunction(str)-要在浏览器上计算的JavaScript函数的字符串,此函数采用与选择器匹配的元素作为第一个参数。

args(Any)-传递给pageFunction的参数。

如果没有元素匹配,则此方法会引发错误selector

click()

click() 方法模拟鼠标单击元素。

此方法可用于执行对元素的单击,就像用户手动单击它一样。

pyppeteer的学习链接:

https://www.cnblogs.com/eliwang/p/14948012.html

爬取Openjudge自己提交通过的所有程序源码

复制代码
# 爬取Openjudge自己提交通过的所有程序源码

import asyncio
import pyppeteer as pyp
import time

import nest_asyncio
nest_asyncio.apply()

async def antiAntiCrawler(page):
#为page添加反反爬虫手段
    await page.setUserAgent('Mozilla/5.0 (Windows NT 6.1; Win64; x64) \ '
    'AppleWebKit/537.36 (KHTML, like Gecko) '
    'Chrome/78.0.3904.70 Safari/537.36')
    await page.evaluateOnNewDocument(
    '() =>{ Object.defineProperties(navigator,'
    '{ webdriver:{ get: () => false } }) }')

    
async def getOjSourceCode(loginUrl):
    width, height = 1400, 800 #网页宽高
    browser = await pyp.launch(headless=False, executablePath = r"E:\Download_Softwear\chromium\chrome-win\chrome-win\chrome.exe",
    args=[f'--window-size={width},{height}'])
    
    page = await browser.newPage()
    await antiAntiCrawler(page) #为page页面提供反爬虫手段
    await page.setViewport({'width': width, 'height': height})
    await page.goto(loginUrl)
    #若手动登录,则以下若干行可以去掉
    '''
    如果没有定义class或者有多个相同的class时可以通过id获取,区别在于class传参是 "." 加class名称  
    而id传参是  "#" 加id名称
    '''
    element = await page.querySelector("#email") #找到账户输入框
    await element.type("你的账号") # 输入邮箱
    element = await page.querySelector("#password") #找到密码输入框
    await element.type("你的密码") # 输入密码
#     type(): 往输入框中输入内容,第一个参数为 CSS 选择器,第二个为文本内容

    element = await page.querySelector("#main > form > div.user-login >p:nth-child(2) > button") #找到登录按钮
     
    await element.click() # 点击登录按钮
#     click() 方法模拟鼠标单击元素。此方法可用于执行对元素的单击,就像用户手动单击它一样。

    #若手动登录,则以上若干行可以去掉

    await page.waitForSelector("#main>h2",timeout=30000) #等待"正在进行的比赛...."标题出现
    element = await page.querySelector("#userMenu>li:nth-child(2)>a")
    #找"个人首页"链接
    await element.click() #点击个人首页链接
    await page.waitForNavigation() #等新网页装入完毕
    elements = await page.querySelectorAll(".result-right")
    # class传参是 "." 加class名称
    #找所有"Accepted"链接, 其有属性 class="result-right"
    
    page2 = await browser.newPage() #新开一个页面 (标签)
    await antiAntiCrawler(page2)

    for element in elements[:2]: #只打印前两个程序
        obj = await element.getProperty("href") #获取href属性
        url = await obj.jsonValue()
        await page2.goto(url) #在新页面(标签)中装入新网页
        element = await page2.querySelector("pre") #查找pre tag
        obj = await element.getProperty("innerText") #取源代码
        text = await obj.jsonValue()
        print(text)
        print("-------------------------")
        
    time.sleep(10)
    
    await browser.close()
                                       
def main():
    url = "http://openjudge.cn/auth/login/"
    asyncio.get_event_loop().run_until_complete(getOjSourceCode(url))
main()

pyppeteer+requests编写快速爬虫

爬取Openjudge自己提交通过的所有程序源码(pyppeteer+requests编写快速爬虫)

复制代码
# 爬取Openjudge自己提交通过的所有程序源码(pyppeteer+requests编写快速爬虫)

import asyncio
import pyppeteer as pyp
import time
import bs4
import requests

import nest_asyncio
nest_asyncio.apply()

def sessionGetHtml(session,url): #发送带session的网页请求
    fakeHeaders = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
    AppleWebKit/537.36 (KHTML, like Gecko) \
    Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.416.77'
    } # 伪装浏览器用的请求头
    try:
        result = session.get(url,headers = fakeHeaders)
#         session的get(url)函数,可以向服务器发送带session的请求
#         获得cookie,生成相应session以后,爬取网页都用session的get函数进行

        result.encoding = result.apparent_encoding
        return result.text
    except Exception as e:
        print(e)
        return ""

async def makeSession(page):
# 返回一个session,将其内部cookies修改成pypeteer浏览器页面对象中的cookies
    cookies = await page.cookies() #cookies是一个列表,每个元素都是一个字典
#     pyppeteer的浏览器的页面有cookies()函数可以获得cookie

    cookies1 = {}
    for cookie in cookies: # requests中的cookies只要 "name"属性
        cookies1[cookie['name']] = cookie['value']
    session = requests.Session()
#     requests.Session()可以生成一个空session

    session.cookies.update(cookies1)
#     session的cookies.update(cookies)函数可以根据cookies生成相应session

    return session
# 获得cookie,生成相应session以后,爬取网页都用session的get函数进行

    '''
    pyppeteer的浏览器的页面有cookies()函数可以获得cookie
    requests.Session()可以生成一个空session
    session的cookies.update(cookies)函数可以根据cookies生成相应session
    session的get(url)函数,可以向服务器发送带session的请求
    获得cookie,生成相应session以后,爬取网页都用session的get函数进行
    (前提:网页不是javascript生成的。如果是,依然用pyppeteer的浏览器爬取
    '''

async def antiAntiCrawler(page):
#为page添加反反爬虫手段
    await page.setUserAgent('Mozilla/5.0 (Windows NT 6.1; Win64; x64) \ '
    'AppleWebKit/537.36 (KHTML, like Gecko) '
    'Chrome/78.0.3904.70 Safari/537.36')
    await page.evaluateOnNewDocument(
    '() =>{ Object.defineProperties(navigator,'
    '{ webdriver:{ get: () => false } }) }')

    
async def getOjSourceCode(loginUrl):
    width, height = 1400, 800 #网页宽高
    browser = await pyp.launch(headless=False, executablePath = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
    args=[f'--window-size={width},{height}'])
    
    page = await browser.newPage()
    await antiAntiCrawler(page)
    await page.setViewport({'width': width, 'height': height})
    await page.goto(loginUrl)
    #若手动登录,则以下若干行可以去掉
    element = await page.querySelector("#email") #找到账户输入框
    await element.type("你的邮箱") # 输入邮箱
    element = await page.querySelector("#password") #找到密码输入框
    await element.type("你的密码") # 输入密码
    
    element = await page.querySelector("#main > form > div.user-login >p:nth-child(2) > button") #找到登录按钮
     
    await element.click() # 点击登录按钮
    #若手动登录,则以上若干行可以去掉

    await page.waitForSelector("#main>h2",timeout=30000) #等待"正在进行的比赛...."标题出现
    element = await page.querySelector("#userMenu>li:nth-child(2)>a")
    #找"个人首页"链接
    await element.click() #点击个人首页链接
    await page.waitForNavigation() #等新网页装入完毕
    elements = await page.querySelectorAll(".result-right")
    #找所有"Accepted"链接, 其有属性 class="result-right"
    
    session = await makeSession(page)
    for element in elements[:1]:
        print("element\n", element)
        obj = await element.getProperty("href")
        url = await obj.jsonValue()
        html = sessionGetHtml(session, url)
        soup = bs4.BeautifulSoup(html, "html.parser")
        element = soup.find("pre")
        print(type(element))
        if(element != None):
            print(element.text)
        print("-------------------------")
    await browser.close()

    '''
    page2 = await browser.newPage() #新开一个页面 (标签)
    await antiAntiCrawler(page2)

    for element in elements[:2]: #只打印前两个程序
        obj = await element.getProperty("href") #获取href属性
        url = await obj.jsonValue()
        await page2.goto(url) #在新页面(标签)中装入新网页
        element = await page2.querySelector("pre") #查找pre tag
        obj = await element.getProperty("innerText") #取源代码
        text = await obj.jsonValue()
        print(text)
        print("-------------------------")
        
    time.sleep(10)
    
    await browser.close()
    '''

def main():
    url = "http://openjudge.cn/auth/login/"
    asyncio.get_event_loop().run_until_complete(getOjSourceCode(url))
main()

爬取豆瓣电影top250的电影名称:

爬取豆瓣电影top250的电影名称(完整代码与解释)-CSDN博客

相关推荐
数据智能老司机2 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机3 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机3 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机3 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i4 小时前
drf初步梳理
python·django
每日AI新事件4 小时前
python的异步函数
python
这里有鱼汤5 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python
databook14 小时前
Manim实现脉冲闪烁特效
后端·python·动效
程序设计实验室14 小时前
2025年了,在 Django 之外,Python Web 框架还能怎么选?
python
倔强青铜三16 小时前
苦练Python第46天:文件写入与上下文管理器
人工智能·python·面试