python操作流程及爬取豆瓣图片

常见的数据来源

类别 解释 例子
开放数据源 重要是行业数据库,政府公开的各类数据 国家统计局、wind、巨潮资讯网
爬虫爬取的数据 通过爬虫取得的数据 豆瓣、社交网站、电商网站、图片网站
传感器采集 通过传感器采集到的数据
日志采集 应用埋点采集到的数据

爬取数据的工具

火车采集器。 可以做抓取工具,也可以做数据清洗、数据分析、数据挖掘和可视化等工作。

八爪鱼。 可以实现自动云采集。

集搜客。 缺点是没有云采集功能,所有爬虫都是在用户自己电脑上跑的。

爬虫的操作流程

爬虫模拟我们日常获取网页信息的流程,通过计算机程序自动化爬取内容。

包括三个阶段:

  • 打开网页。工具为Requests ,数据包括 HTML 页面以及 JSON 数据。
  • 爬取数据。针对HTML页面使用XPath 提取数据,针对JSON数据使用JSON 库进行解析。
  • 保存数据。可以使用Pandas 保存数据,导出为CSV 文件。

三个阶段解析

Requests

Requests有两种访问方式,Get和Post。

其中Get把参数包含在链接中。

1  

|

r = requests.get('http://www.douban.com')  
  

—|—

Post通过request body传递参数。

1  

|

r = requests.post('http://xxx.com', data = {'key', 'value'})  
  

—|—

data的数据结构是字典,通过key 和 value 对数据储存。

动态数据需要通过XHR发出HTTP请求。

Xpath

XPath 是 XML 的路径语言,帮助定位位置。

使用Xpath解析规则

在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。

表达式 描述
node 选取此节点的所有子节点
/ 从根节点选取
// 选取所有的当前节点,不考虑位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性
或,两个节点的合并
text() 当前路径下的文版内容

下面用这个网站上的例子举例:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  

|

<?xml version="1.0" encoding="ISO-8859-1"?>  
  
<bookstore>  
  
<book>  
  <title lang="eng">Harry Potter</title>  
  <price>29.99</price>  
</book>  
  
<book>  
  <title lang="eng">Learning XML</title>  
  <price>39.95</price>  
</book>  
  
</bookstore>  
  

—|—

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

xpath(’//@id’) 选取所有的 id 属性;

xpath(’//book[@id]’) 选取所有拥有名为 id 的属性的 book 元素;

xpath(’//book[@id=“abc”]’) 选取所有 book 元素,且这些 book 元素拥有 id= “abc”的属性;

xpath(’//book/title | //book/price’) 选取 book 元素的所有 title 和 price 元素。

定位到所有列表项目,需要使用lxml,下面代码为定位到HTML所有列表函数。

1  
2  
3  

|

from lxml import etree  
html = etree.HTML(html)  
result = html.xpath('//li')  
  

—|—

JSON

Json.dumps():将python对象转换成ISON对象。

Json.load():将python对象转换成JSON对象。

1  
2  
3  
4  
5  
6  
7  

|

import json  
  
jsonData = '{"a":1,"b":2,"c":3,"d":4,"e":5}';  
  
input = json.loads(jsonData)  
  
print(input)  
  

—|—

输出结果为:

1  

|

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}  
  

—|—

项目实战:爬取葛优相关图片

步骤一:打开网页

打开豆瓣图片,输入关键词葛优

image-20200901195719609

步骤二:选择图片

在搜索结果中,可以看到网页是动态的(即往下滑可以看到更多的图片),动态数据需要通过XHR发出HTTP请求,此处需要知道JSON。

我们先来寻找XHR结构,方法是通过:1)谷歌浏览器右键单击检查;2)选择Network;3)选择XHR;4)刷新页面。从图片中可以看到共有1724张葛优相关的图片。

image-20200901200213885

从上图最下面的方框中可以看到JSON。可以看到数据被放到images里面,每张图片通过字典形式储存,元数据包含author、height、id、src、title、width等信息,有了这些信息,我们便可以提取需要的数据。

在看一下图片的组成,limit:20,最大可以显示20张,第一张图片从0开始,我们便可以写个for循环实现所有的下载。

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  

|

images: [{src: "https://img3.doubanio.com/view/photo/photo/public/p399074242.jpg", author: "饭",…},…]  
0: {src: "https://img3.doubanio.com/view/photo/photo/public/p399074242.jpg", author: "饭",…}  
author: "饭"  
height: 600  
id: "399074242"  
src: "https://img3.doubanio.com/view/photo/photo/public/p399074242.jpg"  
title: "葛优"  
url: "https://www.douban.com/link2/?url=http%3A%2F%2Fwww.douban.com%2Fphotos%2Fphoto%2F399074242%2F&query=%E8%91%9B%E4%BC%98&cat_id=1025&type=search"  
width: 414  
limit: 20  
more: true  
total: 1724  
  

—|—

提取需要的信息

找到了网页及所需要的信息,接下里就是提取所需要的数据,并且进行储存。

完整代码如下:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  

|

# -*- coding:utf-8 -*-  
import requests  
import json  
query = '葛优'  
  
# 下载图片  
def download(src, id):  
  dir = './' + str(id) + '.jpg'  
  try:  
    pic = requests.get(src, timeout=10)  
    fp = open(dir, 'wb')  
    fp.write(pic.content)  
    fp.close()  
  except requests.exceptions.ConnectionError:  
    print('图片无法下载')  
              
# for 循环 请求全部的 url  
for i in range(0, 1723, 20):  
  url = 'https://www.douban.com/j/search_photo?q='+query+'&limit=20&start='+str(i)  
  html = requests.get(url).text    # 得到返回结果  
  response = json.loads(html, encoding='utf-8') # 将 JSON 格式转换成 Python 对象  
  for image in response['images']:  
    print(image['src']) # 查看当前下载的图片网址  
    download(image['src'], image['id']) # 下载一张图片  
  

—|—

参考资料

Xpath教程

ChangeLog

20201029 补充Xpath案例,仍然出现错误Expecting value: line 1 column 1 (char 0)

20200901 爬虫代码运行错误