过程分析

参考:https://mp.weixin.qq.com/s/ET9HP2n3905PxBy4ZLmZNw

首先是书籍排行榜的地址:

http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-1

我们要的就是前 500 本书的:排名,书名,图片地址,作者,推荐指数,五星评分次数,价格

查看源码,可以得到这些信息放在<li>标签中

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
<li>
<div class="list_num red">2.</div>
<div class="pic"><a href="http://product.dangdang.com/25197810.html" target="_blank"><img src="http://img3m0.ddimg.cn/33/33/25197810-1_l_3.jpg" alt="尤尔小屋的猫" title="尤尔小屋的猫"></a></div>
<div class="name"><a href="http://product.dangdang.com/25197810.html" target="_blank" title="尤尔小屋的猫">尤尔小屋的猫</a></div>
<div class="star"><span class="level"><span style="width: 96.4%;"></span></span><a href="http://product.dangdang.com/25197810.html?point=comment_point" target="_blank">138068条评论</a><span class="tuijian">100%推荐</span></div>
<div class="publisher_info"><a href="http://search.dangdang.com/?key=莉莉·海沃德" title="莉莉·海沃德、译者张玫瑰,酷威文化 出品" target="_blank">莉莉·海沃德</a>、<a href="http://search.dangdang.com/?key=译者张玫瑰" title="莉莉·海沃德、译者张玫瑰,酷威文化 出品" target="_blank">译者张玫瑰</a>,<a href="http://search.dangdang.com/?key=酷威文化" title="莉莉·海沃德、译者张玫瑰,酷威文化 出品" target="_blank">酷威文化</a> 出品</div>
<div class="publisher_info"><span>2018-01-01</span>&nbsp;<a href="http://search.dangdang.com/?key=百花洲文艺出版社" target="_blank">百花洲文艺出版社</a></div>

<div class="biaosheng">五星评分:<span>65923次</span></div>


<div class="price">
<p><span class="price_n">¥31.30</span>
<span class="price_r">¥39.80</span>(<span class="price_s">7.9折</span>)
</p>
<p class="price_e"></p>
<div class="buy_button">
<a ddname="加入购物车" name="" href="javascript:AddToShoppingCart('25197810');" class="listbtn_buy">加入购物车</a>

<a ddname="加入收藏" id="addto_favorlist_25197810" name="" href="javascript:showMsgBox('addto_favorlist_25197810',encodeURIComponent('25197810&amp;platform=3'), 'http://myhome.dangdang.com/addFavoritepop');" class="listbtn_collect">收藏</a>

</div>

</div>

</li>

首先是主函数:

用page实现翻页,使用 requests 请求当当网,然后将返回的 HTML 进行正则解析,最后保存到txt文件里

1
2
3
4
5
6
7
8
9
10
def main(page):
url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-' + str(page)
html = request_dandan(url)
items = parse_result(html)
for item in items:
write_item_to_file(item)

if __name__ == "__main__":
for i in range(1, 26):
main(i)

然后逐个实现各个函数:

1
2
3
4
5
6
7
def request_dandan(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
except requests.RequestException:
return None

这里调用了requests模块向服务器发送get请求,get请求去指定的url获取网页数据,随后对响应码作了判断,200代表获取成功,成功就返回获取的响应数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def parse_result(html):
pattern = re.compile(
'<li>.*?list_num.*?(\d+).</div>.*?<img src="(.*?)".*?class="name".*?title="(.*?)">.*?class="star">.*?class="tuijian">(.*?)</span>.*?class="publisher_info">.*?target="_blank">(.*?)</a>.*?class="biaosheng">.*?<span>(.*?)</span></div>.*?<p><span\sclass="price_n">&yen;(.*?)</span>.*?</li>',
re.S)
items = re.findall(pattern, html)
for item in items:
yield { #这里的不是很明白,等待后续学习
'range': item[0],
'iamge': item[1],
'title': item[2],
'recommend': item[3],
'author': item[4],
'times': item[5],
'price': item[6]
}

这里使用compile对正则表达式进行封装,并用findall查找所用匹配项

yield 的用法可以参考:

来具体看一看正则表达式:

1
<li>.*?list_num.*?(\d+).</div>

这一句匹配的是

1
2
<li>
<div class="list_num red">1.</div>

注意,\d+被括号括起来了,代表将匹配的这部分内容(即图中的1这个数字)捕获并作为1个元素存放到了一个数组中,所以现在匹配结果对应的数组中(即item)第一个元素是1,也就是排名。

剩下的正则表达式类似,就不多讲了

最后写入文件:

1
2
3
4
def write_item_to_file(item):
print('开始写入数据 ====> ' + str(item))
with open('book.txt', 'a', encoding='UTF-8') as f:
f.write(json.dumps(item, ensure_ascii=False) + '\n')

完整代码

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
import requests
import re
import json


def request_dandan(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
except requests.RequestException:
return None


def parse_result(html):
pattern = re.compile(
'<li>.*?list_num.*?(\d+).</div>.*?<img src="(.*?)".*?class="name".*?title="(.*?)">.*?class="star">.*?class="tuijian">(.*?)</span>.*?class="publisher_info">.*?target="_blank">(.*?)</a>.*?class="biaosheng">.*?<span>(.*?)</span></div>.*?<p><span\sclass="price_n">&yen;(.*?)</span>.*?</li>',
re.S)
items = re.findall(pattern, html)
for item in items:
yield {
'range': item[0],
'iamge': item[1],
'title': item[2],
'recommend': item[3],
'author': item[4],
'times': item[5],
'price': item[6]
}


def write_item_to_file(item):
print('开始写入数据 ====> ' + str(item))
with open('book.txt', 'a', encoding='UTF-8') as f:
f.write(json.dumps(item, ensure_ascii=False) + '\n')


def main(page):
url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-' + str(page)
html = request_dandan(url)
items = parse_result(html)
for item in items:
write_item_to_file(item)


if __name__ == "__main__":
for i in range(1, 26):
main(i)