round1:爬取的是用户个人介绍,本来以为直接response.xpath('//span[@id="intro_display"]/text()'.get()
不香吗,结果别人整个链接,然后只能爬取博客地址。如果直接用extract(),又只会返回列表。
这边我用user['introduction'] = "".join(response.xpath('//span[@id="intro_display"]/text()').re(r"(.*)"))
得到的是:
blog地址:看书,写字,出去走走,喜欢历史,喜欢老旧的东西,喜欢老旧的东西后面藏着的故事,非常好奇,时时提醒自己别太贪心。。。
也可以不用正则表达式。
结果基本令人满意
round2:豆瓣模拟登录
今天终于实现了模拟登录,也就意味着可以爬取任意数量的某一部电影的短评了。
给出自己的模拟登录的代码:
import scrapy
from scrapy.spiders import Request
from movie250.items import MovieUser
import movie250.database as db
from scrapy.http import FormRequest
from faker import Factory
cursor = db.conn.cursor()
f = Factory.create() # 这个利用faker库生成一个user-agent
class DoubanSpider(scrapy.Spider):
name = 'douban3'
allowed_domains = ['movie.douban.com', 'douban.com']
headers = {
'Accept': 'text/html,appresponsecation/xhtml+xml,appresponsecation/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Connection': 'keep-aresponseve',
'Host': 'accounts.douban.com',
'User-Agent': f.user_agent()
}
formdata = { #来源见下文
'form_email': 'xxxxxxxxxxxxxx', #
'form_password': 'xxxxxxxxxxxxxx',#
'ck': 'BLPW',
'remember': 'true',
}
# 采取的思路是将登陆后重定向的网址给下载下来,然后对照一下,好确认。
def start_requests(self):
return [Request(url='https://movie.douban.com', meta={'cookiejar': 1}, callback=self.parse_login)]
def parse_login(self, response):
print('Loging...')
return FormRequest(url='https://accounts.douban.com/j/mobile/login/basic',
formdata=self.formdata,
method='POST',
headers=self.headers,
meta={'cookiejar': response.meta['cookiejar']},
dont_filter=True,
callback=self.parse_users #登陆完成后开始访问我们需要的页面
)
def parse_users(self, response): # 不要少了response参数,否则parse_users() takes 1 positional argument but 2 were given
sql = "SELECT people_url from test.comment250 group by people_url;"
cursor.execute(sql)
users = cursor.fetchall()
for i in users:
url = i['people_url']
yield Request(url=url, callback=self.movieuser_parse)
def movieuser_parse(self, response): #与模拟登录无关
user = MovieUser()
user['user_URL'] = response.url
# print(response.extract())
user['people_name'] = response.xpath("//*[@id='db-usr-profile']/div[2]/h1/text()").get().strip()
# print(user['rank'])
user['join_date'] = response.xpath("//*[@id='profile']/div/div[2]/div[1]/div/div/text()[2]").re_first(
r"(\d+-\d+\d+)")
user['location'] = response.xpath("//*[@id='profile']/div/div[2]/div[1]/div/a/text()").get().strip()
user['introduction'] = "".join(response.xpath('//span[@id="intro_display"]/text()').re(r"(.*)")) # 因为有些评论
user['follow'] = response.xpath("//*[@id='friend']/h2/span/a/text()").re_first(
r"(\d+)") # 该函数可以提取第一个匹配到的字符串:https://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/selectors.html
user['followed'] = response.xpath("//*[@id='content']/div/div[2]/p[1]/a/text()").re_first(r"(\d+)")
print(user['introduction'])
yield user
formdata来源
然后你就可以看到需要的东西。
不足之处:如果有滑动验证码怎么办?
听说selenium可以,但是效率低?目前不是重点。
round3:这边由于
原本最多是220条短评,除了有些不同页面会有重复的短评之外也不至于又这么少,这边我打算把上少于211条影评的再爬一边,要用到嵌套查询:
先查询少于211影评的movie_id
SELECT count(*),movie_id FROM test.comment250 group by movie_id having count(*)<211;
再嵌套运行:
SELECT * FROM test.movie250 where movie_id IN(SELECT movie_id FROM test.comment250 group by movie_id having count(*)<211);
但是以后完全没必要用嵌套语句,实在是太慢了把!!!!
round5:查询再top250中热评数最多的人
round6:mysql中出现 ERROR 1052 (23000): Column ‘movie_id’ in field list is ambiguous
列’ID’在字段列表中重复,其实就是两张表有相同的字段,但是使用时表字段的名称前没有加表名,导致指代不明,前面加上前缀movie250就没问题了。
round7:(1406, “Data too long for column ‘introduction’ at row 1”)
introduction varchar(255) COLLATE utf8mb4_unicode_ci,
varchar(255)太小了,我直接给他text了