学习使用python爬虫获得当当网好评榜TOP500
1、需要用到的库
- requests;
- re;
- json;
2、前置知识
- 一点点前端知识:调用浏览器的开发者工具;
- re模块的正则表达式;
3、思路
通过访问好评榜得到其网址
url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-recent30-0-0-1-1'
打开浏览器自带开发者工具-Network-Headers,查找到榜单中关于书的属性。
编写程序get得到相关属性并保存。
4、代码
点击查看代码
import json
import re
import requests
def request_dangdang(url):
try:
response = requests.get(url) # 获取网站返回的Response
if response.status_code == 200: # 代码为200代表正常,对应404、502之类异常状态
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 class="price_n">(.*?)</span>.*?</li>',
re.S) # 查找符合要求的数据的正则表达式(即好评榜中的书目)
items = re.findall(pattern, html) # 找到这些关键词
for item in items: # 存放(yield没明白具体使用方法)
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_dangdang(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)
5、相关知识
1. re正则表达式
常用语法和标识符:
字符 | 功能 | 举例 |
---|---|---|
[...] | 匹配方括号内的字符 | [abc]可以匹配ade、[A-Z]可以匹配Book |
[^...] | 匹配除方括号内的字符 | 与上面相似 |
\s | 匹配空格字符,包括换行 | |
\S | 匹配非空白符,不包括换行 | |
\w | 匹配字母、数字、下划线字符 | |
\d | 匹配一个数字字符 | |
\D | 匹配一个非数字字符 | |
^ | 匹配字符串起始位置 | |
$ | 匹配字符串结束位置 | |
{n} | 匹配前一个字符n次 | o{2}可以匹配'book' |
{n,} | 匹配前一个字符至少n次 | |
{n,m} | 匹配前一个字符至少n次,至多m次 | |
. | 匹配除换行符(\n、\r)之外的任何单个字符 | |
* | 匹配前一个字符0次或多次 | 等价于{0,} |
+ | 匹配前一个字符至少一次 | 等价于 {1,} |
? | 匹配前一个字符0次或1次 | 等价于{0,1} |
https://www.runoob.com/regexp/regexp-flags.html
2. yield
就目前网络看到的各种讲解,yield存在两方面的作用:
- 一方面从某种程度上替换掉return,可以起到暂停或跳出子函数并同时返回yield后面的值或变量;
- 另一方面yield将子函数变为一个迭代器,使其替代range()函数,方便快捷的获取迭代值。
如runoob.com的《Python yield 使用浅析》中“输出斐波那契數列前 N 个数”所说:
对于这个问题可以简单写出如下代码。
点击查看代码
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a + b
n = n + 1
fab(5)
采用yield可写为:
点击查看代码
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 使用 yield
# print b
a, b = b, a + b
n = n + 1
for n in fab(5):
print n
采用yield后将fab()函数转变为一个迭代器,这样输出将成为一个序列。(即使我们也可以通过list.append()的方式将第一种方法的输出结果变为列表,但用于存储的空间复杂度将会有很大差距。)
同时变成迭代器的fab()可以使用.next()函数执行一次迭代。但在python3中应使用 .__next__() 或 .send() 。