网络爬虫
示例:获取百度图片的搜索结果图片(用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()