增量抓取:
数据库内存储指纹信息,下一次在爬取之前先去数据库进行比对,如果不存在则爬取,反之不抓。
动态加载数据抓取Ajax:
- 右键查看网页源代码没有具体信息
- 通过滚动鼠标滑轮或其他动作触发加载,或者页面的局部刷新。
抓取:
以某瓣为例进行抓取,因为这个网页是典型利用ajax动态异步加载实现的。
目标是找出那个地址返回的json数据,找到改地址就能向改地址发请求,获取数据。XHR
根据实际情况处理查询参数,好在豆瓣的get请求没有涉及到加密。
以豆瓣电影抓取电影信息为例:
在consoles table中并没有发现任何数据,网页源代码中也没有,怀疑为异步加载出来的数据,所以分析xhr,滑动页面,发现数据包被依次展示出来,找到数据交互的url地址,找规律。
利用requests.get().json
可以直接自动转化成python的数据结构,按照字典或列表的形式取出值,而不用处理字符串了。
上代码:
import requests
import json
from fake_useragent import UserAgent
import re
from prettytable import PrettyTable
import pymysql
class Spider(object):
def __init__(self):
self.base_url = 'https://movie.douban.com/j/chart/top_list?' \
'type={}&interval_id=100%3A90&action=&start={}&limit={}'
self.count_url = 'https://movie.douban.com/j/chart/top_list_count?' \
'type={}&interval_id=100%3A90'
self.category_url = 'https://movie.douban.com/chart'
self.headers = {'User-Agent': UserAgent().random}
self.database = pymysql.connect(
host='localhost', user='root', password='zza20020321', charset='utf8',
database='doubandb'
)
self.cursor = self.database.cursor()
def get_category(self):
html = requests.get(
url=self.category_url,
headers=self.headers
).text
pattern = re.compile('.*?<span><a href="/typerank.*?type_na'
'me=(.*?)&type=(.*?)&interval_id', re.S)
re_list = pattern.findall(html) # [('', ''), ('', ''), ....]
L = []
L2 = []
item = {}
quary_string = 'select count(0) from type where type_name = %s'
for name_id in re_list:
item[name_id[0]] = name_id[1]
L2.append(name_id[0])
# L2 和item中一定要存储当前的信息以便于向顾客展示选择什么信息来输入输出
if self.if_exists(quary_string, name_id[0])[0] == 0:
t = (
name_id[1], name_id[0]
)
L.append(t)
else:
pass
# 保存到数据库
sql_string = 'insert into type values(%s, %s)'
self.save_to_sql(sql_string, L)
return L2, item
def get_count(self, type):
url = self.count_url.format(type)
count = requests.get(
url=url,
headers=self.headers
).json()['total']
return count
def if_exists(self, sql_string, name):
db = self.database
cursor = self.cursor
cursor.execute(sql_string, name)
flag = cursor.fetchone()
db.commit()
return flag
def save_to_sql(self, sql_string, ins_data):
self.cursor.executemany(sql_string, ins_data)
self.database.commit()
def parse_html(self, base_url):
req = requests.get(
headers=self.headers,
url=base_url
)
py_form_data = req.json()
L = []
L2 = []
sql_string = 'select count(0) from film_info where title = %s'
film_info = PrettyTable(['电影名', '豆瓣排名', '上映日期', '豆瓣评分'])
for py_data in py_form_data:
flag = self.if_exists(sql_string, py_data['title'])[0]
film_info.add_row([py_data['title'], py_data['rank'],
py_data['release_date'], py_data['score']])
if flag == 0:
t = (
py_data['title'], py_data['rank'],
py_data['release_date'], py_data['score']
)
L.append(t)
else:
pass
print('电影信息如下,正在保存数据库~~~~~')
print(film_info)
# 保存到数据库中
sql_string = 'insert into film_info values(%s, %s, %s, %s)'
self.save_to_sql(sql_string, L)
print('数据库信息保存成功~~~~')
def show_category(self):
lists, item = self.get_category()
table = PrettyTable(['1', '2', '3', '4'])
table.add_row(lists[0:4])
table.add_row(lists[5:9])
table.add_row(lists[10:14])
table.add_row(lists[15:19])
table.add_row(lists[20:24])
table.add_row(lists[25:29])
print(table)
def run(self):
lists, item = self.get_category()
self.show_category() # print the table about movie category
types = input('请输入您要查看的电影类型:')
start = input('从第几个开始?')
limit = input('展示几个?')
film_id = item[types]
count = self.get_count(film_id)
real_url = self.base_url.format(film_id, start, limit)
self.parse_html(real_url)
if __name__ == '__main__':
spider = Spider()
spider.run()