准备工作
http请求头概念
1、Accept :请求报头域,用于指定客户端可接受哪些类型的信息。
2、Accept-Language :指定客户端可接受的语言类型。
3、Accept-Encoding :指定客户端可接受的内容编码。
4、Host :用于指定请求资源的主机IP 和端口号,其内容为请求URL 的原始服务器或网关的位
置。从HTTP 1. l 版本开始,请求必须包含此内容。
5、Cookie :也常用复数形式Cookies ,这是网站为了辨别用户进行会话跟踪而存储在用户本地
的数据。它的主要功能是维持当前访问会话。例如,我们输入用户名和密码成功登录某个网
站后,服务器会用会话保存登录状态信息,后面我们每次刷新或请求该站点的其他页面时,
会发现都是登录状态,这就是Cookies 的功劳。Cookies 里有信息标识了我们所对应的服务器
的会话,每次浏览器在请求该站点的页面时,都会在请求头中加上Cookies 并将其发送给服
务器,服务器通过Cookies 识别出是我们自己,并且查出当前状态是登录状态,所以返回结
果就是登录之后才能看到的网页内容。
6、Referer :此内容用来标识这个请求是从哪个页面发过来的,服务器可以拿到这一信息并做相
应的处理,如做来源统计、防盗链处理等。
7、User-Agent :简称UA ,它是一个特殊的字符串头,可以使服务器识别客户使用的操作系统
及版本、浏览器及版本等信息。在做爬虫时加上此信息,可以伪装为浏览器;如果不加,很
可能会被识别州为爬虫。
8、Content-Type :也叫互联网媒体类型( Internet Media Type )或者MIME 类型,在HTTP 协议
消息头中,它用来表示具体请求中的媒体类型信息。例如, text/html 代表HTML 格式,
image/gif代表GIF 图片, app lication/json 代表JSON 类型,更多对应关系可以查看此对照表:
http://tool.oschina.net/commons
Python3.7官方文档 https://docs.python.org/3.7/whatsnew/3.7.html
编程规范
1、每个缩进层级使用4个空格
2、每行最多79个字符
3、顶层函数或类的定义之间空两行(特别容易漏,漏的话,是报E302 expected 2 blank lines, found 1)
4、采用ASCII或者UTF-8编码文件
5、每条import导入一个模块,导入放在代码顶端,导入顺序是先标准库,第三方库,本地库
6、 小括号,大括号,中括号之间的逗号没有额外的空格
7、类命名采用骆驼命名法,CamelCase;函数用小写字符
8、函数命名使用小写字符,例如xxx_xxx_xxx;用下划线开头定义私有的属性或方法,如_xxx
1、识别网站所用技术
pip install builtwith # 用于识别网站使用技术
# 安装模块,识别网站技术
# pip install builtwith
import builtwith
# 执行识别命令
print(builtwith.parse('http://example.webscraping.com'), '\n')
2、寻找网站所有者 PS暂时不知道这步的作用
# pip install python-whois
import whois
print(whois.whois('http://sanberd.com'),'\n')
print(whois.whois('http://example.webscraping.com'),'\n')
3、下载网页(抓取)
模拟GET请求和POST请求
# import urllib 这样引入 会报request未定义。。。。。。
import socket
import urllib.parse
import urllib.request
import urllib.error
# 模拟get请求
def download (url ):
print('Downloading :',url)
try :
response = urllib.request.urlopen(url)
print(type(response))
# print(response.read().decode('utf-8'))
except urllib.request.URLError as e :
print('Download error :',e.reason)
response = None
return response
download('https://www.python.org')
# data = download('http://www.sanberd.com/')
# print(data)
# 模拟post请求
def downloadbydata(url):
try:
postdata = bytes(urllib.parse.urlencode({'word':'hello'}), encoding='utf-8')
print(postdata)
# 设置超时时间 0.1 秒
response = urllib.request.urlopen(url, data=postdata,timeout=0.1)
print(response.read().decode('utf-8'))
except urllib.request.URLError as e:
if isinstance(e.reason, socket.timeout):
print('TIME OUT')
downloadbydata('http://httpbin.org/post')
完整模拟请求
from urllib import request, parse
#伪装火狐浏览器
# Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11
# 谷歌浏览器
# Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
url = 'http://httpbin.org/post'
header = {
# 'User-Agent': 'Mozilla/4.0 (compatible;MSIE 5.5;Windows NT)',
# 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)',
'User-Agent': 'Mozilla/5.0 (X11; U; Linux i686)',
'Host':'httpbin.org'
}
dict = {
'name':'Germey'
}
data= bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=header, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
遇到的第一个坑,导入自定义模块,模块文件不在当前文件目录,
需要设置导入目录,设置 support.py与当前文件同一个目录
#!/usr/bin/python3
# 文件名: support.py
import sys
import os
# 设置自定义搜索路径
bp = os.path.dirname(os.path.realpath('.')).split(os.sep)
# print(bp)
modpath = os.sep.join(bp + ['utils'])
# print(modpath)
sys.path.insert(0, modpath)
print(sys.path)
在需要导入自定义模块的文件里执行
#!/usr/bin/python3
# 文件名: pachong003.py
import urllib.request
import urllib.error
import support
import 自定义模块的文件名
这样就可以把自己写的模块统一放到一个文件夹里,然后按需要引入了。
不过,这样写会报 [flake8] 引入模块 imported but unused [F401] 语法错误,看的郁闷,
所以,我取消了 flake8使用。。。。。。第一次搞这个,能有结果就行。。。
"python.linting.flake8Enabled": false, //启用flake8,首先需要pip3 install
#!/usr/bin/python3
# 文件名: pachong_dali.py
from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener
# 模拟设置代理
proxy_handler = ProxyHandler({'http': '127.0.0.1'})
opener = build_opener(proxy_handler)
try:
response = opener.open('https://www.baidu.com')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
下面一个完整样例,照着书敲了好一会,才调通,正则表达式伤不起啊,,
抓取猫眼网站源码
#!/usr/bin/python3
# 抓取猫眼电影网站
import json
import requests
from requests.exceptions import RequestException
import re
import time
# 取页面
def get_one_page(url):
try:
headers = {
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac 0S X 10_11_4) AppleWebKit/537.36 (KHTML, lik Gecko)Chrome/52.0.2743.116 Safari/537.36'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
# 取内容
# 取排名 <dd>.*?board-index.*?>(.*?)</i>
# 取图片 .*?data-src="(.*?)"
# 取名称 .*?name.*?a.*?>(.*?)</a>
# 取主演 .*?star.*?>(.*?)</p>
# 取发布时间 .*?releasetime.*?>(.*?)</p>
# 取评分 .*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>
def parse_one_page(html):
pattern = re.compile(
'<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>',
re.S)
# pattern = re.compile(
# r'<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?</dd>', re.S)
items = re.findall(pattern, html)
# strip 删除字符串开始于末尾的空格
for item in items:
yield {
'index': item[0],
'image': item[1],
'title': item[2].strip(),
'actor': item[3].strip()[3:] if len(item[3]) > 3 else '',
'time': item[4].strip()[5:] if len(item[4]) > 5 else '',
'score': item[5].strip() + item[6].strip()
}
return items
def write_to_file(content):
# 写文件 a 追加模式
with open('result.txt', 'a', encoding='utf-8') as f:
# print(type(json.dumps(content)))
f.write(json.dumps(content, ensure_ascii=False) + '\n')
# 读文件
# with open('result.txt', 'r', encoding='utf-8') as f:
# f.readlines()
def main(offset):
url = 'https://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
for item in parse_one_page(html):
# print(item)
# print(json.dumps(item, ensure_ascii=False) + '\n')
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
print('开始抓取 第' + str(i + 1) + '次,')
main(offset=i * 10)
print('抓取完成 歇3秒', '\n')
time.sleep(3)
# if __name__ == '__main__':
# print('程序自身在运行')
# else:
# print('我来自另一模块')
# $ python using_name.py
# 程序自身在运行
# $ python
# >>> import using_name
# 我来自另一模块