啦啦啦,滴滴答,我是卖报的小行家,今天终于完成长达两天的python爬虫的学习了
今天的总结呢,包括以下几点:
一.关于基础知识的归类
爬取基本过程
1.选着要爬的网址 (url)
2.使用 python 登录上这个网址 (urlopen等)
3.读取网页信息 (read() 出来)
4.将读取的信息放入 BeautifulSoup
5.选取 需要的tag 信息等
登录网站的方式
- urlopen:
from urllib.request import urlopen
# if has Chinese, apply decode()
html = urlopen(
"https://mofanpy.com/static/scraping/basic-structure.html"
).read().decode('utf-8')
print(html)
- request:
1)get:
import requests
import webbrowser
param = {"wd": "莫烦Python"} # 搜索的信息
#它会将我们搜索的关键词以及wd:和前面固定格式组成一个url
r = requests.get('http://www.baidu.com/s', params=param)
print(r.url)
#打开链接
webbrowser.open(r.url)
2)post:
登录
#要投入的信息
data = {'firstname': '莫烦', 'lastname': '周'}
#要投入的链接requesturl而不是当前网页链接
r = requests.post('http://pythonscraping.com/files/processing.php', data=data)
print(r.text)
- driver
from selenium import webdriver
driver = webdriver.Chrome() # 打开 Chrome 浏览器
# 将刚刚复制的帖在这
driver.get("https://mofanpy.com/")
driver.find_element_by_xpath(u"//img[@alt='强化学习 (Reinforcement Learning)']").click()
driver.find_element_by_link_text("About").click()
driver.find_element_by_link_text(u"赞助").click()
driver.find_element_by_link_text(u"教程 ▾").click()
driver.find_element_by_link_text(u"数据处理 ▾").click()
driver.find_element_by_link_text(u"网页爬虫").click()
# 得到网页 html内容
html = driver.page_source # get html
#,还能网页截图
driver.get_screenshot_as_file("./img/sreenshot1.png")
driver.close()
这种方式使用selenium模拟对浏览器的操作,其中模拟对浏览器的操作是通过安装火狐浏览器中一个叫Katalon Recorder插件实现自动生成代码的。
解析网页的方式
- BS4
输出内容
from bs4 import BeautifulSoup
from urllib.request import urlopen
# if has Chinese, apply decode()
html = urlopen("https://mofanpy.com/static/scraping/basic-structure.html").read().decode('utf-8')
print(html)
soup = BeautifulSoup(html, features='lxml')
print(soup.h1)
print('\n', soup.p)
<a href="https://mofanpy.com/tutorials/scraping">爬虫教程</a>
all_href = soup.find_all('a')
print(all_href)
for l in all_href]:
print(l.["href"])
print('\n', all_href)
按class匹配信息
soup = BeautifulSoup(html, features='lxml')
# use class to narrow search
month = soup.find_all('li', {"class": "month"})
for m in month:
#获得所收集到的列表中所夹的文本信息
print(m)
print(m.get_text())
结合正则
soup = BeautifulSoup(html, features='lxml')
#找soup里所有img标签,他的属性用正则来匹配
img_links = soup.find_all("img", {"src": re.compile('.*?\.jpg')})
for link in img_links:
print(link['src'])
- 正则表达式
import re
from urllib.request import urlopen
# if has Chinese, apply decode()
html = urlopen(
"https://mofanpy.com/static/scraping/basic-structure.html"
).read().decode('utf-8')
print(html)
res = re.findall(r"<title>(.+?)</title>", html)
print("\nPage title is: ", res[0])
res = re.findall(r"<p>(.*?)</p>", html, flags=re.DOTALL) # re.DOTALL if multi line
print("\nPage paragraph is: ", res[0])
# Page title is: Scraping tutorial 1 | 莫烦Python
res = re.findall(r"<p>(.*?)</p>", html, flags=re.DOTALL) # re.DOTALL if multi line
print("\nPage paragraph is: ", res[0])
# Page paragraph is:
# 这是一个在 <a href="https://mofanpy.com/">莫烦Python</a>
# <a href="https://mofanpy.com/tutorials/scraping">爬虫教程</a> 中的简单测试.
res = re.findall(r'href="(.*?)"', html)
print("\nAll links: ", res)
# All links:
['https://mofanpy.com/static/img/description/tab_icon.png',
'https://mofanpy.com/',
'https://mofanpy.com/tutorials/scraping']
加速爬虫的方式
- 多进程
- 异步
特殊功能
- session
同样是执行上面的登录操作, 下面就是使用 session 的版本. 创建完一个 session 过后, 我们直接只用 session 来 post 和 get. 而且这次 get 的时候, 我们并没有传入 cookies. 但是实际上 session 内部就已经有了之前的 cookies 了.
session = requests.Session()
payload = {'username': 'Morvan', 'password': 'password'}
r = session.post('http://pythonscraping.com/pages/cookies/welcome.php', data=payload)
print(r.cookies.get_dict())
# {'username': 'Morvan', 'loggedin': '1'}
r = session.get("http://pythonscraping.com/pages/cookies/profile.php")
print(r.text)
# Hey Morvan! Looks like you're still logged into the site!
- 下载
1)urlretrieve
from urllib.request import urlretrieve
urlretrieve(IMAGE_URL, './img/image1.png')
2)request
正常下载
import requests
#将网址内容下载存在r中
r = requests.get(IMAGE_URL)
with open('./img/image2.png', 'wb') as f:
#将r中的内容写入到文件中
f.write(r.content)
批量下载
r = requests.get(IMAGE_URL, stream=True) # stream loading
with open('./img/image3.png', 'wb') as f:
for chunk in
r.iter_content(chunk_size=32):
f.write(chunk)
二.环境配置
1.request:pip3 install requests
2.beautifulsoup4:pip3 install beautifulsoup4
3.4.pip3 install selenium
三.实践过程的心酸历程(爬取百度图片)
爬取位置:https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1616152719672_R&pv=&ic=&nc=1&z=&hd=&latest=©right=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&sid=&word=%E8%9F%AA%E8%9B%84/
直接使用别人代码
from bs4 import BeautifulSoup
import requests
URL = "http://www.nationalgeographic.com.cn/animals/"
html = requests.get(URL).text
soup = BeautifulSoup(html, 'lxml')
div_ul = soup.find_all('div', {"class": "imgpage"})
# print(div_ul)
print(len(div_ul))
for ul in div_ul:
imgs = ul.find_all('li', {"class": "imgitem"})
# print(imgs)
print(len(imgs))
print(12345)
for img in imgs:
url = img['data-thumburl']
r = requests.get(url, stream=True)
image_name = url.split('/')[-1]
with open('./img/%s' % image_name, 'wb') as f:
for chunk in r.iter_content(chunk_size=128):
f.write(chunk)
print('Saved %s' % image_name)
并将网站和对应匹配方式改成自己观察网页的结果,但是存在以下两个问题:
1.lxml未安装
网址
2.无论如何匹配我在网页中观察到特定类的标签都返回空列表无法匹配,我刚开始以为是我的标签或者对应类的类型书写有误,检查一大顿也没有问题,最后我想输出一下我访问的网页看看到底和我看的网页是不是一个网页,要是一样的话可真就见了鬼了,于是我用下列代码测试:
import requests
import webbrowser
#它会将我们搜索的关键词以及wd:和前面固定格式组成一个url
r = requests.get('https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1616152719672_R&pv=&ic=&nc=1&z=&hd=&latest=©right=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&sid=&word=%E8%9F%AA%E8%9B%84/')
print(r.text())
print(r.url)
#打开链接
webbrowser.open(r.url)
运行结果
https://wappass.baidu.com/static/captcha/tuxing.html?&ak=c27bbc89afca0463650ac9bde68ebe06&backurl=https%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3Dpython&logid=9429735157699859545&signature=ab2baa7ec785cf123cfa8f498a9a0664×tamp=1580387558
解决:
在网上搜了各种绕开百度验证或者破解安全验证的方法,但是有的太复杂,有得不好用,但是有意无意我发现了为什么机器登录会产生验证而 正常人为登录为什么不出现验证码:
我们在使用浏览器正常登录百度指数网站的时候发现一般不会弹出验证码的提示。但是如果你使用无头浏览器去登录的时候就会出现验证码,那么这两者登录的区别在哪里呢?
经过我不断的验证发现了两个问题,当我们使用无头浏览器登录的时候做一些类似于人类的操作,例如在窗口中滑动鼠标,或者改变窗口的大小,这样百度指数网站就会认为你是人为的在操作。
第二个问题就是在我们使用无头浏览器输入账号和密码的时候,我们在手动输入密码的时候或多或少的在输入字符之间都会存在时间间隔,而使用无头浏览器的时候程序会零间隔的输入,这样百度指数网站就会认为你是一个程序在输入了。
所以我想到了一个办法只要浏览器认为不是人打开的浏览器就可以正常访问而不需要进行验证,正好因为 Selenium 需要操控你的浏览器,它能控制你的浏览器, 有模有样地学人类看网页.他就是基于这个浏览器程序来进行操作的,打开浏览,进行点击,输入密码等操作,所以我选择使用它来进行打开网页并得到网页内容进行爬取
使用Selenium
from selenium import webdriver
from bs4 import BeautifulSoup
import requests
import time
driver = webdriver.Chrome() # 打开 Chrome 浏览器
# 将刚刚复制的帖在这
driver.get("https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1616152719672_R&pv=&ic=&nc=1&z=&hd=&latest=©right=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&sid=&word=%E8%9F%AA%E8%9B%84/")
# 得到网页 html内容
html = driver.page_source # get html
# print(html)
print(2)
soup = BeautifulSoup(html, 'lxml')
div_ul = soup.find_all('div', {"class": "imgpage"})
# print(div_ul)
print(len(div_ul))
for ul in div_ul:
imgs = ul.find_all('li', {"class": "imgitem"})
# print(imgs)
print(len(imgs))
print(12345)
for img in imgs:
url = img['data-thumburl']
r = requests.get(url, stream=True)
image_name = url.split('/')[-1]
with open('./image/%s' % image_name, 'wb') as f:
for chunk in r.iter_content(chunk_size=128):
f.write(chunk)
print('Saved %s' % image_name)
#,还能网页截图
driver.get_screenshot_as_file("./image/sreenshot1.png")
这样就可以完美避过验证但是也存在三个问题:
1.需要下载驱动才能使selenium控制浏览器
报错:Selenium: Runtime.executionContextCreated has invalid ‘context’:
1)首先在查看你查看自己chrome浏览器的版本
2.下载对应版本的驱动
下载网址
我的版本是89.0.4389.23/
点进去,虽然是win64但是win32仍然好用
注:一定要下载对应版本的驱动否则会报错如下,别问我咋知道的,因为我也刚爬出坑,哈哈
WebDriverException: Message: unknown error: Runtime.executionContextCreated has invalid ‘context’
3.解压缩文件,并将driver.exe文件放在chrome.exe文件的同级目录中
我的电脑是:C:\Users\123\AppData\Local\Google\Chrome\Application
4.将刚才所放文件位置的路径添加系统环境路径Path中
5.如果是使用anaconda环境的话,重启命令行,重新加载路径,报错消失
2.如何编写对网页操作的selenium代码
1.下载火狐浏览器
下载网址、
2.安装插件Katalon Recorder
也可以直接在火狐中搜索插件并直接安装,安装后要进行激活和注册
3.插件的使用,如果安装完成会在下图位置处显示
4.实现记录
5.导出代码
3.如何爬取网页所有的内容
第三个问题就是我看到有很多类型imgpage的div里面img类型的li标签中存的是图片并可以通过其中data-thumburl属性获得网址并下载,而我们反复实验就只能下载20张图片,我们只能下载第一个类型imgpage的div里面img类型的li标签中存的图片,别imgpage的div里面无法匹配的到,自然也就无法下载,我突然发现有的时候我只能找到一个类型imgpage的div,也就是我能下载的那些图片所在div,而有些时候我可以查看到所有该类型的div
后来我发现原来你刚打开网页的时候只会显示并加载第一页的图片,也就只能加载一个div内容,而随着你下拉滑块查看网页所有内容,此时div才会逐渐添加到中,这是用jsp写的动作,只有你向下拉动滚动条才会在中添加网页之前未显示的内容,网页的源代码不断更新,是网页的一种行为,所以我们要打开网页之后读取网页内容之前不断下拉滑块,显示网页所有内容是网页源代码中包含网页所有内容。
解决:
转载于:https://www.zhihu.com/question/46528604?sort=created
定义一个函数,实现将滚轮滑到页面最下方的功能,这个在官方文档中有(为了让页面载入完整,每5秒下移一次,一共下移10次)
def execute_times(times):
for i in range(times + 1):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
execute_times(10)
4.我的代码和结果
from selenium import webdriver
from bs4 import BeautifulSoup
import requests
import time
driver = webdriver.Chrome() # 打开 Chrome 浏览器
# 将刚刚复制的帖在这
driver.get("https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1616152719672_R&pv=&ic=&nc=1&z=&hd=&latest=©right=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&sid=&word=%E8%9F%AA%E8%9B%84/")
print(1)
def execute_times(times):
for i in range(times + 1):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
execute_times(10)
# 得到网页 html内容
html = driver.page_source # get html
# print(html)
print(2)
soup = BeautifulSoup(html, 'lxml')
div_ul = soup.find_all('div', {"class": "imgpage"})
# print(div_ul)
print(len(div_ul))
for ul in div_ul:
imgs = ul.find_all('li', {"class": "imgitem"})
# print(imgs)
print(len(imgs))
print(12345)
for img in imgs:
url = img['data-thumburl']
r = requests.get(url, stream=True)
image_name = url.split('/')[-1]
with open('./image/%s' % image_name, 'wb') as f:
for chunk in r.iter_content(chunk_size=128):
f.write(chunk)
print('Saved %s' % image_name)
#,还能网页截图
driver.get_screenshot_as_file("./image/sreenshot1.png")