avatar

爬虫回顾之Ajax

Ajax

Ajax,全称为 Asynchronous JavaScript and XML,即异步的 JavaScript 和 XML。它不是一门编程语言,而是利用 JavaScript在保证页面不被刷新、页面链接
不改变的情况下与服务器交换数据并更新部分网页的技术。

基本原理

发送 Ajax 请求到网页更新的过程可以简单分为以下 3 步:

  1. 发送请求
  2. 解析内容
  3. 渲染网页

发送请求

1
2
3
4
5
6
7
8
9
10
11
12
13
var xmlhttp;

if (window.XMLHttpRequest) {
xmlhttp=new XMLHttpRequest();}
else {
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}

xmlhttp.onreadystatechange=function() {if (xmlhttp.readyState==4 && xmlhttp.status==200) {document.getElementById("myDiv").innerHTML=xmlhttp.responseText;}
}

xmlhttp.open("POST","/ajax/",true);
xmlhttp.send()

这是 JavaScript 对 Ajax 最底层的实现,这个过程实际上是新建了 XMLHttpRequest 对象,然后调用 onreadystatechange 属性设置监听,最后调用 open() 和 send() 方法向某个链接(也就是服务器)发送请求。

解析内容

得到响应之后,onreadystatechange 属性对应的方法会被触发,此时利用 xmlhttp 的 responseText 属性便可取到响应内容。这类似于 Python 中利用 requests 向服务器发起请求,然后得到响应的过程。

返回的内容可能是 HTML,也可能是 JSON,接下来我们只需要在方法中用 JavaScript 进一步处理即可。比如,如果返回的内容是 JSON 的话,我们便可以对它进行解析和转化。

渲染网页

JavaScript 有改变网页内容的能力,解析完响应内容之后,就可以调用 JavaScript 针对解析完的内容对网页进行下一步处理。比如,通过document.getElementById().innerHTML 这样的操作,对某个元素内的源代码进行更改,这样网页显示的内容就改变了,这种对 Document 网页文档进行如更改、删除等操作也被称作 DOM 操作。

selenium

Selenium 是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面源代码,做到可见即可爬。对于一些使用 JavaScript 动态渲染的页面来说,此种抓取方式非常有效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from urllib.parse import urljoin
from os import makedirs
from os.path import exists
import logging
import json
import time


RESULTS_DIR = 'selenium-results'
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)

logging.basicConfig(level=logging.INFO,
format = '%(asctime)s - %(levelname)s: %(message)s')

INDEX_URL = 'https://dynamic2.scrape.cuiqingcai.com/page/{page}'
TIME_OUT = 30
TOTAL_PAGE = 10

options = webdriver.ChromeOptions()
options.add_argument('--headless')
browser = webdriver.Chrome(options=options)
wait = WebDriverWait(browser, TIME_OUT)

def scrape_page(url, condiion, locator):
logging.info('scrapping %s···' % url)
try:
browser.get(url)
wait.until(condiion(locator))
except TimeoutException:
logging.error('error occurred while  scraping  %s '%url, exc_info=True )

def scrape_index(page):
url = INDEX_URL.format(page=page)
scrape_page(url, condiion=EC.visibility_of_all_elements_located, locator=(By.CSS_SELECTOR, '#index .item'))

def parse_index():
elements = browser.find_elements_by_css_selector('#index .item .name')
for element in elements:
href = element.get_attribute('href')
yield urljoin(INDEX_URL, href)

def scrape_details(url):
scrape_page(url, condiion=EC.visibility_of_element_located, locator=(By.TAG_NAME, 'h2'))

def parse_detail():
url = browser.current_url
name = browser.find_element_by_tag_name('h2').text
categories = [element.text for element in browser.find_elements_by_css_selector('.categories button span')]
cover = browser.find_element_by_css_selector('.cover').get_attribute('src')
drama = browser.find_element_by_css_selector('.drama p').text
score = browser.find_element_by_xpath('//*[@id="detail"]/div[1]/div/div/div[1]/div/div[3]/p[1]').text
time.sleep(3)
return {
'url': url,
'name': name,
'categories': categories,
'cover': cover,
'score': score,
'drama': drama
}

def save_data(data):
name = data.get('name')
data_path = f'{RESULTS_DIR}/{name}.json'
json.dump(data, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)


def main():
try:
for page in range(1, TOTAL_PAGE+1):
scrape_index(page)
detail_urls = parse_index() # 此处的detail_urls是个生成器
for detail_url in list(detail_urls):
scrape_details(detail_url)
detail_data = parse_detail()
save_data(detail_data)
logging.info('detaildata %s' % detail_data)
finally:
browser.close()

if __name__ == '__main__':
main()
文章作者: gh
文章链接: https://ghclub.top/posts/44696/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 GHBlog
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论