最近在看崔庆才老师的爬虫视频,这里借鉴一下视频的代码做一个豆瓣新书的爬虫,主要是熟悉一下爬虫的流程,不用解析库是想熟悉一下正则表达式和网页结构,本来想爬当当网的,那个网页结构有点复杂,正则表达式没写出来。。。打算后面用解析库试试。下面说一下整个流程:
1)抓取网页,函数get_page(url);
2)解析网页内容,函数parse_page(html);
3)存入文档,函数write_to_file(content)。
下面是整个代码
粗糙版
import json
import requests
import re
for i in range(3):
page = i+1
url = 'https://market.douban.com/book/?utm_campaign=book_nav_freyr&utm_source=douban&utm_medium=pc_web&page='\
+ str(page) + '&page_num=18&'
response = requests.get(url).text
pattern = re.compile('<li.*?bookface-img">.*?src="(.*?)".*?book-price.*?<i>(.*?)</i>.*?book-brief.*?'
+ '<h3>(.*?)</h3>.*?</li>', re.S)
result = re.findall(pattern, response)
for item in result:
yiel = {
'faceimg': item[0],
'price': item[1],
'brief': item[2]
}
print(yiel)
with open('r1.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(yiel, ensure_ascii=False) + '\n')
f.close()
精致版
import json
import requests
import re
from requests.exceptions import RequestException
def get_page(url):
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
def parse_page(html):
pattern = re.compile('<li.*?bookface-img">.*?src="(.*?)".*?book-price.*?<i>(.*?)</i>.*?book-brief.*?'
+ '<h3>(.*?)</h3>.*?</li>', re.S)
result = re.findall(pattern, html)
for item in result:
yield {
'faceimg': item[0],
'price': item[1],
'brief': item[2]
}
def write_to_file(content):
with open('result.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n') # 把字典转换成字符串 json.loads()把字符串转换成字典
f.close()
def main(page):
url = 'https://market.douban.com/book/?utm_campaign=book_nav_freyr&utm_source=douban&utm_medium=pc_web&page='\
+ str(page) + '&page_num=18&'
html = get_page(url)
for item in parse_page(html):
print(item)
write_to_file(item)
if __name__ == "__main__":
for i in range(3):
main(i+1)
最后的结果大概是这样
在整个实现过程中,个人遇到的主要问题如下
注:
1)看懂网页结构,这里每一本新书的信息都包含在<li></li>标签里面,根据class等参数提取相应信息;
2)def函数中return和print的问题
比如
def test(num):
print(num)
test(33)
print(test(33))
返回
此处返回了3个结果,前两个结果都是执行了函数test,
最后一个None是print(test(33))的结果,原因在于test函数可以运行,但是没有return任何值,pycharm也提示Function 'test' doesn't return anything
def test(num):
return num
test(33)
print(test(33))
返回
test函数返回num对象,将其打印输出。
3)和第2点也相关,yield函数的使用
一个带有 yield 的函数就是一个生成器,每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
4)字符编码和数据类型问题
open.write()中内容参数必须为字符串,此处利用json.dumps()方法将字典转化为字符串,反之,将字符串转化成字典的函数是json.loads()。
其中json.dumps()中的参数ensure_ascii默认为True,利用ascii编码,同时需要设置txt文件的编码格式。
网友评论