爬取目标
目标网站:https://dynamic1.scrape.cuiqingcai.com/
详情页
先尝试用requests来直接提取页面
import requestsurl = 'https://dynamic1.scrape.cuiqingcai.com/'html = requests.get(url).textprint(html)
运行结果
可以发现数据都是通过Ajax来加载的,JavaScript在后台调用这些Ajax数据接口,得到数据之后,再把数据进行解析并渲染呈现出来,得到最终的页面。
首先分析下列表页的Ajax接口逻辑,打开浏览器开发者工具,切换到Network面板,勾选Preserve Log并切换到XHR选项卡。
点击第2页、第3页、第4页的按钮,观察数据变化,同时在开发者工具下监听Ajax请求
观察其中一个Ajax请求,点击查看请求详情
可以看到Ajax接口请求的URL地址为:https://dynamic1.scrape.cuiqingcai.com/api/movie/?limit=10&offset=10
有两个参数,一个是limit,其值为10,一个是offset,值也是10。
可以发现limit的值一直为10,正好对应每页10条数据;offset的值在依次变大,页面每加1页,offset就加10,说明代表页面的数据偏移量。
在观察响应的数据,切换到Preview
结果是JSON数据,有一个results字段,这是一个列表,列表的每一个元素都是一个字典。
只需要把所有页面的Ajax接口构造出来,那么所有的列表页数据就可以获取到。
爬取列表页
导入所需的库并定义配置
import requestsimport logginglogging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')INDEX_URL = 'https://dynamic1.scrape.cuiqingcai.com/api/movie/?limit={limit}&offset={offset}'
引入requests和logging库,并定义了logging的基本配置,接着定义INDEX_URL,把limit和offset预留出来变成占位符,动态传入构造成一个完整的列表URL。
定义爬取方法
def scrape_api(url): logging.info('scraping %s...', url) try: response = requests.get(url) if response.status_code == 200: return response.json() logging.error('get invalid status code %s while scraping %s', response.status_code, url) except requests.RequestException: logging.error('error occurred while scraping %s', url, exc_info=True)
定义一个方法,专门用来处理JSON接口,最后的response调用的是json方法,它可以解析响应的内容并将其转换成JSON字符串。
爬取列表页
LIMIT = 10def scrape_index(page): url = INDEX_URL.format(limit=LIMIT, offset=LIMIT * (page - 1)) return scrape_api(url)
定义scrape_index方法,用来接受参数page,page代表列表页的页码。
这里构造了一个URL,通过字符串的format方法,传入limit和offset的值。这里的limit直接使用了全局变量LIMIT的值,offset则是动态计算的,计算方法是页码数减1再乘以limit。构造好URL之后,直接调用scrape_api方法并返回结果。
由于这时爬取到的数据已经是JSON类型了,所以不用去解析HTML代码来提取数据。