有的网站比如京东我们用request
爬取的HTML和看到的网页不同,是因为实际的网页是通过JavaScript处理而成。
为了解决这个问题,我们可以用模拟浏览器的方式来实现爬取。
Python
提供了很多模拟浏览器的库, 比如Selenuim
, Splash
等等。使用这些库可以完成对动态渲染页面的爬取。
Selenuim
是一个自动化测试工具,利用它可以驱动浏览器做特定的动作,比如点击,下拉等操作。同时还可以获得当前页面的源代码。
pip install selenium
同时还需要安装ChromeDriver
来配合使用
在ChromeDriver官网选择合适自己浏览器版本的ChromeDriver
安装.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")
try:
brower.get('https://www.baidu.com')
input = brower.find_element_by_id('kw')
input.send_keys('Python')
input.send_keys(Keys.ENTER)
wait = WebDriverWait(brower, 10)
wait.until(EC.presence_of_all_elements_located((By.ID,
'content_left')))
print(brower.current_url)
print(brower.page_source)
finally:
brower.close()
运行代码后会自动跳出一个浏览器,然后转到百度,输入Python
并搜索,然后跳转到搜索结果页。控制台输出当前URL后,浏览器推出
除此之外page_source
,会返回浏览器的真实内容,也就是可以拿到渲染之后的结果了。
Selenium
支持很多浏览器,常见的Chrome、Edge、FireFox等
from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Edge()
browser = webdriver.Firefox()
browser = webdriver.Safari()
这样就完成了浏览器对象的初始化并赋值给了browser,下面要做的就是调用这个对象,让其执行各种操作。
可以使用get()
来请求页面, 参数传入链接URL即可。比如访问淘宝
brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")
brower.get("https://www.taobao.com")
print(brower.page_source)
brower.close()
运行后,浏览器会自动访问淘宝,然后输出淘宝页面的源代码,然后浏览器关闭。
Selenium
可以驱动浏览器完成各种操作,比如刚刚向输入框里面输入文字的操作。但是如何找到输入框的?Selenium
提供了一系列的查找节点的方法
比如想要从淘宝页面提取搜索框,就需要观察他的源代码
它的id是q, name也是q。除此之外还有其他很多属性。这是就可以使用find_element_by_name()
或者find_element_by_id()
来选择它
brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")
brower.get("https://www.taobao.com")
input = brower.find_element_by_id('q')
print(input)
brower.close()
<selenium.webdriver.remote.webelement.WebElement (session="78c516397ce008e8697ca516d2ed2487", element="64515e6e-5fc3-439f-affb-857a90fd9d32")>
除此之外,还有函数find_element()
,需要传入两个参数方式By
和值, 如:
find_element(By.ID, id)
其实是上面两个函数的通用版本。
如果想要查找的目标在网页中只有一个, 那就完全可以用find_element()
方法,但是如果有多个节点,find_element()
方法就只能获取第一个, 可以用要用find_elements()
Selenium
可以模拟浏览器执行一些操作,比如常见的, 输入文字send_keys()
,点击按钮的click
等
brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")
brower.get("https://www.taobao.com")
input = brower.find_element_by_id('q')
input.send_keys('ipad')
time.sleep(1)
input.clear()
input.send_keys('iphone')
button = brower.find_element_by_class_name('btn-search')
button.click()
brower.close()
获取输入框后输入ipad,等待一秒后删掉,然后输入iphone,找到搜索按钮,然后搜索。
前面的结果用page_source
可以获得网页的源代码,之后就可以用解析库提取信息了。
Selenium
同样提供了获取节点信息的方法
- 获取属性
get_attribute()
- 获取文本
text
, 每个WebElement节点都有text属性,调用就可以获取文本信息
对于浏览器的前进后退Selenium
提供了back()
和forward()
brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")
brower.get("https://www.taobao.com")
brower.get("https://www.baidu.com")
brower.get("https://www.python.org")
brower.back()
brower.forward()
brower.close()
# ipad
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
from urllib.parse import quote
from pyquery import PyQuery as pq
brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")
wait = WebDriverWait(brower, 10)
KEYWORD = 'ipad'
def index_page(page):
print('正在爬取第', page, '页')
try:
url = 'https://s.taobao.com/search?q=' + quote(KEYWORD)
brower.get(url)
if page > 1:
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager div.form > input')))
submit = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager div.form > span.btn.J_Submit'))
)
input.clear()
input.send_keys(page)
submit.click()
wait.until(
EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'),
str(page)))
wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '.m-itemlist .items .item')))
get_products()
except TimeoutException:
index_page(page)
def get_products():
html = brower.page_source
doc = pq(html)
items = doc('#mainsrp-itemlist .items .item').items()
for item in items:
product = {
'image':item.find('.pic .img').attr('data-src'),
'price':item.find('.price').text(),
'shop':item.find('.shop').text()
}
print(product)
MAX_PAGE = 3
def main():
for i in range(1, MAX_PAGE + 1):
index_page(i)
main()